Skip to content

Commit

Permalink
Apply spotless to all java projects (#3184)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasTu committed Nov 29, 2023
1 parent b6554b2 commit 290a8e1
Show file tree
Hide file tree
Showing 64 changed files with 1,313 additions and 1,208 deletions.
23 changes: 1 addition & 22 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ allprojects { proj ->
plugins.withId('java') {
proj.apply from: "$rootDir/gradle/errorprone.gradle"
proj.apply from: "$rootDir/gradle/jfr.gradle"
proj.apply from: "$rootDir/gradle/spotless.gradle"
}
tasks.withType(JavaCompile).configureEach {
//I don't believe those warnings add value given modern IDEs
Expand Down Expand Up @@ -118,25 +119,3 @@ animalsniffer {
'java.lang.StackWalker$Option'
]
}

spotless {
// We run the check separately on CI, so don't run this by default
enforceCheck = false

java {
licenseHeaderFile rootProject.file('config/spotless/spotless.header')

custom 'google-java-format', { source ->
com.google.googlejavaformat.java.JavaFormatterOptions options = new com.google.googlejavaformat.java.AutoValue_JavaFormatterOptions.Builder()
.style(com.google.googlejavaformat.java.JavaFormatterOptions.Style.AOSP)
.formatJavadoc(false)
.reorderModifiers(true)
.build()
com.google.googlejavaformat.java.Formatter formatter = new com.google.googlejavaformat.java.Formatter(options)
return formatter.formatSource(source)
}

// This test contains emulation of same-line stubbings. The formatter would put them on a separate line.
targetExclude 'src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java'
}
}
33 changes: 33 additions & 0 deletions gradle/spotless.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
buildscript {
repositories {
gradlePluginPortal()
}

dependencies {
classpath 'com.google.googlejavaformat:google-java-format:1.18.1'
}
}

apply plugin: 'com.diffplug.spotless'

spotless {
// We run the check separately on CI, so don't run this by default
enforceCheck = false

java {
licenseHeaderFile rootProject.file('config/spotless/spotless.header')

custom 'google-java-format', { source ->
com.google.googlejavaformat.java.JavaFormatterOptions options = new com.google.googlejavaformat.java.AutoValue_JavaFormatterOptions.Builder()
.style(com.google.googlejavaformat.java.JavaFormatterOptions.Style.AOSP)
.formatJavadoc(false)
.reorderModifiers(true)
.build()
com.google.googlejavaformat.java.Formatter formatter = new com.google.googlejavaformat.java.Formatter(options)
return formatter.formatSource(source)
}

// This test contains emulation of same-line stubbings. The formatter would put them on a separate line.
targetExclude 'src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ public AndroidByteBuddyMockMaker() {
if (Platform.isAndroid() || Platform.isAndroidMockMakerRequired()) {
delegate = new SubclassByteBuddyMockMaker(new AndroidLoadingStrategy());
} else {
Plugins.getMockitoLogger().log(join(
"IMPORTANT NOTE FROM MOCKITO:",
"",
"You included the 'mockito-android' dependency in a non-Android environment.",
"The Android mock maker was disabled. You should only include the latter in your 'androidTestCompile' configuration",
"If disabling was a mistake, you can set the 'org.mockito.mock.android' property to 'true' to override this detection.",
"",
"Visit https://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.1 for more information"
));
Plugins.getMockitoLogger()
.log(
join(
"IMPORTANT NOTE FROM MOCKITO:",
"",
"You included the 'mockito-android' dependency in a non-Android environment.",
"The Android mock maker was disabled. You should only include the latter in your 'androidTestCompile' configuration",
"If disabling was a mistake, you can set the 'org.mockito.mock.android' property to 'true' to override this detection.",
"",
"Visit https://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.1 for more information"));
delegate = new SubclassByteBuddyMockMaker();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,21 @@ public boolean isDisrespectingOpenness() {
}

@Override
public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean localMock) {
public ClassLoadingStrategy<ClassLoader> resolveStrategy(
Class<?> mockedType, ClassLoader classLoader, boolean localMock) {
File target = AndroidTempFileLocator.target;
if (target == null) {
throw new MockitoException(join(
"Could not look up implicit location for storing generated classes",
"",
"You can configure an explicit location by setting the system property",
"'org.mockito.android.target' to a folder for storing generated class files",
"This location must be in private scope for most API versions, for example:",
"",
"MyActivity.this.getDir(\"target\", Context.MODE_PRIVATE)",
"or",
"getInstrumentation().getTargetContext().getCacheDir().getPath()"
));
throw new MockitoException(
join(
"Could not look up implicit location for storing generated classes",
"",
"You can configure an explicit location by setting the system property",
"'org.mockito.android.target' to a folder for storing generated class files",
"This location must be in private scope for most API versions, for example:",
"",
"MyActivity.this.getDir(\"target\", Context.MODE_PRIVATE)",
"or",
"getInstrumentation().getTargetContext().getCacheDir().getPath()"));
}
return new AndroidClassLoadingStrategy.Injecting(target);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

class AndroidTempFileLocator {

final static File target;
static final File target;

static {
File t = null;
Expand All @@ -23,7 +23,9 @@ class AndroidTempFileLocator {
} catch (Throwable ignored) {
}
if (t == null) {
t = getCacheDirFromInstrumentationRegistry("android.support.test.InstrumentationRegistry");
t =
getCacheDirFromInstrumentationRegistry(
"android.support.test.InstrumentationRegistry");
}
if (t == null) {
t = getCacheDirFromInstrumentationRegistry("androidx.test.InstrumentationRegistry");
Expand All @@ -33,7 +35,8 @@ class AndroidTempFileLocator {
Class<?> clazz = Class.forName("dalvik.system.PathClassLoader");
Field pathField = clazz.getDeclaredField("path");
pathField.setAccessible(true);
String pathFromThisClassLoader = (String) pathField.get(AndroidTempFileLocator.class.getClassLoader());
String pathFromThisClassLoader =
(String) pathField.get(AndroidTempFileLocator.class.getClassLoader());
File[] results = guessPath(pathFromThisClassLoader);
if (results.length > 0) {
t = results[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,103 +27,107 @@

/** Base for {@link BugChecker}s that detect issues with any() matchers and primitive types. */
public abstract class AbstractMockitoAnyForPrimitiveType extends BugChecker
implements MethodInvocationTreeMatcher {

protected abstract Matcher<? super MethodInvocationTree> matcher();

protected abstract String formatMessage(
String expectedTypeAsString, Type matcherType, String replacementName);

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!matcher().matches(tree, state)) {
return NO_MATCH;
}

MethodSymbol method = ASTHelpers.getSymbol(tree);
Type matcherType = method.getReturnType();

// It is expected that the call to anyX() is itself the argument to another call which is
// the one being mocked, e.g. something like this:
// when(mock.call(..., anyInt(), ...))...
TreePath path = state.getPath();
Tree parentTree = path.getParentPath().getLeaf();
if (!(parentTree instanceof MethodInvocationTree)) {
// Ignore calls that are not arguments to another method call.
// TODO: Report this as a problem because it makes little sense.
// TODO: Support casting.
return NO_MATCH;
}

MethodInvocationTree parentCall = (MethodInvocationTree) parentTree;
MethodSymbol parentMethod = ASTHelpers.getSymbol(parentCall);

// Find the index of the argument in the parent call.
int argumentIndex = -1;
List<? extends ExpressionTree> parentArguments = parentCall.getArguments();
for (int i = 0; i < parentArguments.size(); i++) {
ExpressionTree argumentTree = parentArguments.get(i);
if (argumentTree == tree) {
argumentIndex = i;
break;
}
}
if (argumentIndex == -1) {
throw new IllegalStateException(
"Cannot find argument " + state.getSourceForNode(tree) + " in argument list from " + state.getSourceForNode(parentTree));
}

Type parameterType = getParameterType(parentMethod, argumentIndex);

TypeKind parameterTypeKind = parameterType.getKind();
if (parameterTypeKind.isPrimitive() && parameterTypeKind != matcherType.getKind()) {
String expectedTypeAsString = parameterType.toString();
String replacementName =
"any"
+ Character.toUpperCase(expectedTypeAsString.charAt(0))
+ expectedTypeAsString.substring(1);

String message = formatMessage(expectedTypeAsString, matcherType, replacementName);

SuggestedFix.Builder fixBuilder = SuggestedFix.builder();

ExpressionTree methodSelect = tree.getMethodSelect();
String replacement;
if (methodSelect instanceof MemberSelectTree) {
MemberSelectTree qualifier = (MemberSelectTree) methodSelect;
replacement = state.getSourceForNode(qualifier.getExpression()) + "." + replacementName;
} else {
replacement = replacementName;
String staticImport = method.owner + "." + replacementName;
fixBuilder.addStaticImport(staticImport);
}

SuggestedFix fix = fixBuilder.replace(tree, replacement + "()").build();

return buildDescription(tree).setMessage(message).addFix(fix).build();
implements MethodInvocationTreeMatcher {

protected abstract Matcher<? super MethodInvocationTree> matcher();

protected abstract String formatMessage(
String expectedTypeAsString, Type matcherType, String replacementName);

@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
if (!matcher().matches(tree, state)) {
return NO_MATCH;
}

MethodSymbol method = ASTHelpers.getSymbol(tree);
Type matcherType = method.getReturnType();

// It is expected that the call to anyX() is itself the argument to another call which is
// the one being mocked, e.g. something like this:
// when(mock.call(..., anyInt(), ...))...
TreePath path = state.getPath();
Tree parentTree = path.getParentPath().getLeaf();
if (!(parentTree instanceof MethodInvocationTree)) {
// Ignore calls that are not arguments to another method call.
// TODO: Report this as a problem because it makes little sense.
// TODO: Support casting.
return NO_MATCH;
}

MethodInvocationTree parentCall = (MethodInvocationTree) parentTree;
MethodSymbol parentMethod = ASTHelpers.getSymbol(parentCall);

// Find the index of the argument in the parent call.
int argumentIndex = -1;
List<? extends ExpressionTree> parentArguments = parentCall.getArguments();
for (int i = 0; i < parentArguments.size(); i++) {
ExpressionTree argumentTree = parentArguments.get(i);
if (argumentTree == tree) {
argumentIndex = i;
break;
}
}
if (argumentIndex == -1) {
throw new IllegalStateException(
"Cannot find argument "
+ state.getSourceForNode(tree)
+ " in argument list from "
+ state.getSourceForNode(parentTree));
}

Type parameterType = getParameterType(parentMethod, argumentIndex);

TypeKind parameterTypeKind = parameterType.getKind();
if (parameterTypeKind.isPrimitive() && parameterTypeKind != matcherType.getKind()) {
String expectedTypeAsString = parameterType.toString();
String replacementName =
"any"
+ Character.toUpperCase(expectedTypeAsString.charAt(0))
+ expectedTypeAsString.substring(1);

String message = formatMessage(expectedTypeAsString, matcherType, replacementName);

SuggestedFix.Builder fixBuilder = SuggestedFix.builder();

ExpressionTree methodSelect = tree.getMethodSelect();
String replacement;
if (methodSelect instanceof MemberSelectTree) {
MemberSelectTree qualifier = (MemberSelectTree) methodSelect;
replacement =
state.getSourceForNode(qualifier.getExpression()) + "." + replacementName;
} else {
replacement = replacementName;
String staticImport = method.owner + "." + replacementName;
fixBuilder.addStaticImport(staticImport);
}

SuggestedFix fix = fixBuilder.replace(tree, replacement + "()").build();

return buildDescription(tree).setMessage(message).addFix(fix).build();
}

return NO_MATCH;
}

return NO_MATCH;
}

/**
* Get the type of the parameter for a supplied argument.
*
* @param method the method symbol that is being called.
* @param argumentIndex the index of the argument, can be greater than the number of parameters
* for a var arg method.
* @return the type of the associated parameter.
*/
private Type getParameterType(MethodSymbol method, int argumentIndex) {
List<VarSymbol> parameters = method.getParameters();
Type parameterType;
int parameterCount = parameters.size();
if (argumentIndex >= parameterCount && method.isVarArgs()) {
VarSymbol varArgParameter = parameters.get(parameterCount - 1);
parameterType = ((ArrayType) varArgParameter.asType()).getComponentType();
} else {
parameterType = parameters.get(argumentIndex).asType();
/**
* Get the type of the parameter for a supplied argument.
*
* @param method the method symbol that is being called.
* @param argumentIndex the index of the argument, can be greater than the number of parameters
* for a var arg method.
* @return the type of the associated parameter.
*/
private Type getParameterType(MethodSymbol method, int argumentIndex) {
List<VarSymbol> parameters = method.getParameters();
Type parameterType;
int parameterCount = parameters.size();
if (argumentIndex >= parameterCount && method.isVarArgs()) {
VarSymbol varArgParameter = parameters.get(parameterCount - 1);
parameterType = ((ArrayType) varArgParameter.asType()).getComponentType();
} else {
parameterType = parameters.get(argumentIndex).asType();
}
return parameterType;
}
return parameterType;
}
}

0 comments on commit 290a8e1

Please sign in to comment.