Skip to content
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

Migrate Jmockit VerificationsInOrder to Mockito #632

Merged
merged 18 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@
import java.util.ArrayList;
import java.util.List;

import static org.openrewrite.java.testing.jmockit.JMockitBlockType.FullVerifications;
import static org.openrewrite.java.testing.jmockit.JMockitBlockType.NonStrictExpectations;
import static org.openrewrite.java.testing.jmockit.JMockitBlockType.*;

class JMockitBlockRewriter {

private static final String WHEN_TEMPLATE_PREFIX = "when(#{any()}).";
private static final String VERIFY_TEMPLATE_PREFIX = "verify(#{any()}";
private static final String VERIFY_NO_INTERACTIONS_TEMPLATE_PREFIX = "verifyNoMoreInteractions(";
private static final String VERIFY_IN_ORDER_TEMPLATE_PREFIX = "inOrder(";
//private static final String VERIFY_IN_ORDER_TEMPLATE_PREFIX = "InOrder inOrder = inOrder(";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//private static final String VERIFY_IN_ORDER_TEMPLATE_PREFIX = "InOrder inOrder = inOrder(";

Copy link
Collaborator Author

@shivanisky shivanisky Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes - this is one issue I'd like to get input on
inOrder(mock) works, but
InOrder inOrder = inOrder(mock) causes error even though I have the right compilation options and the right import. Hence I am not able to get all the tests passing (have disabled for now).

Caused by: java.lang.IllegalArgumentException: Could not parse as Java
	at org.openrewrite.java.internal.template.JavaTemplateParser.lambda$compileTemplate$13(JavaTemplateParser.java:264)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at org.openrewrite.java.internal.template.JavaTemplateParser.compileTemplate(JavaTemplateParser.java:264)
	at org.openrewrite.java.internal.template.JavaTemplateParser.lambda$parseBlockStatements$9(JavaTemplateParser.java:176)
	at org.openrewrite.java.internal.template.JavaTemplateParser.lambda$cacheIfContextFree$14(JavaTemplateParser.java:287)
	at org.openrewrite.java.internal.template.JavaTemplateParser.cache(JavaTemplateParser.java:308)
	at org.openrewrite.java.internal.template.JavaTemplateParser.cacheIfContextFree(JavaTemplateParser.java:287)
	at org.openrewrite.java.internal.template.JavaTemplateParser.parseBlockStatements(JavaTemplateParser.java:171)
	at org.openrewrite.java.internal.template.JavaTemplateJavaExtension$1.lambda$visitBlock$1(JavaTemplateJavaExtension.java:112)
	at org.openrewrite.internal.ListUtils.lambda$flatMap$0(ListUtils.java:261)
	at org.openrewrite.internal.ListUtils.flatMap(ListUtils.java:205)
	at org.openrewrite.internal.ListUtils.flatMap(ListUtils.java:261)
	at org.openrewrite.java.internal.template.JavaTemplateJavaExtension$1.visitBlock(JavaTemplateJavaExtension.java:110)
	at org.openrewrite.java.internal.template.JavaTemplateJavaExtension$1.visitBlock(JavaTemplateJavaExtension.java:55)
	at org.openrewrite.java.tree.J$Block.acceptJava(J.java:838)
	at org.openrewrite.java.tree.J.accept(J.java:59)
	at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250)
	... 58 more

Copy link
Collaborator Author

@shivanisky shivanisky Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah all good, that parse error went away - thanks, maybe all that was needed was to sync with main! Now just only one test failing with some strange formatting issue, just an empy new line between statements in test whenThreeBlocks g. https://ge.openrewrite.org/s/pyyay4x3zaeui/tests/task/:test/details/org.openrewrite.java.testing.jmockit.JMockitVerificationsInOrderToMockitoTest/whenThreeBlocks()?top-execution=1

Not due to having 3 blocks, but due to having a very short InOrder block of 2 lines.

private static final String LENIENT_TEMPLATE_PREFIX = "lenient().";

private static final String RETURN_TEMPLATE_PREFIX = "thenReturn(";
private static final String THROW_TEMPLATE_PREFIX = "thenThrow(";
private static final String LITERAL_TEMPLATE_FIELD = "#{}";
private static final String ANY_TEMPLATE_FIELD = "#{any()}";
private static final String MOCKITO_IMPORT_FQN_PREFX = "org.mockito.Mockito";
private static final String IN_ORDER_IMPORT_FQN = "org.mockito.InOrder";

private static String getObjectTemplateField(String fqn) {
return "#{any(" + fqn + ")}";
Expand All @@ -53,6 +54,7 @@ private static String getObjectTemplateField(String fqn) {
private final ExecutionContext ctx;
private final J.NewClass newExpectations;
private final JMockitBlockType blockType;
private final List<JMockitBlockType> blockTypes;
// index of the Expectations block in the method body
private final int bodyStatementIndex;
private J.Block methodBody;
Expand All @@ -69,13 +71,14 @@ boolean isRewriteFailed() {
private int numStatementsAdded = 0;

JMockitBlockRewriter(JavaVisitor<ExecutionContext> visitor, ExecutionContext ctx, J.Block methodBody,
J.NewClass newExpectations, int bodyStatementIndex, JMockitBlockType blockType) {
J.NewClass newExpectations, int bodyStatementIndex, JMockitBlockType blockType, List<JMockitBlockType> blockTypes) {
this.visitor = visitor;
this.ctx = ctx;
this.methodBody = methodBody;
this.newExpectations = newExpectations;
this.bodyStatementIndex = bodyStatementIndex;
this.blockType = blockType;
this.blockTypes = blockTypes;
this.nextStatementCoordinates = newExpectations.getCoordinates().replace();
}

Expand Down Expand Up @@ -109,9 +112,7 @@ J.Block rewriteMethodBody() {
methodInvocationIdx++;
methodInvocationsToRewrite.add(new ArrayList<>());
}
if (isFullVerifications() &&
uniqueMocks.stream().noneMatch(mock -> mock.getType().equals(mockObj.getType()) &&
mock.getSimpleName().equals(mockObj.getSimpleName()))) {
if ((isFullVerifications() || isVerificationsInOrder()) && uniqueMocks.stream().noneMatch(mock -> mock.getSimpleName().equals(mockObj.getSimpleName()))) {
uniqueMocks.add(mockObj);
}
}
Expand All @@ -128,11 +129,16 @@ J.Block rewriteMethodBody() {
removeBlock();
}

ArrayList<Object> mocks = new ArrayList<>(uniqueMocks);
shivanisky marked this conversation as resolved.
Show resolved Hide resolved
if (isVerificationsInOrder()) {
rewriteInOrderVerify(mocks);
}

// now rewrite
methodInvocationsToRewrite.forEach(this::rewriteMethodInvocation);

if (isFullVerifications()) {
rewriteFullVerify(new ArrayList<>(uniqueMocks));
rewriteFullVerify(mocks);
}
return methodBody;
}
Expand All @@ -141,6 +147,10 @@ private boolean isFullVerifications() {
return this.blockType == FullVerifications;
}

private boolean isVerificationsInOrder() {
return this.blockType == VerificationsInOrder;
}

private void rewriteMethodInvocation(List<Statement> statementsToRewrite) {
final MockInvocationResults mockInvocationResults = buildMockInvocationResults(statementsToRewrite);
if (mockInvocationResults == null) {
Expand Down Expand Up @@ -223,7 +233,7 @@ private void rewriteVerify(J.MethodInvocation invocation, @Nullable Expression t
// for Verifications, replace the Verifications block
verifyCoordinates = nextStatementCoordinates;
} else {
// for Expectations put the verify at the end of the method
// for Expectations put verify at the end of the method
verifyCoordinates = methodBody.getCoordinates().lastStatement();
}
rewriteTemplate(verifyTemplate, templateParams, verifyCoordinates);
Expand All @@ -243,7 +253,7 @@ private void rewriteVerify(J.MethodInvocation invocation, @Nullable Expression t
}
}

private void rewriteFullVerify(List<Object> mocks) {
private void rewriteFullVerify(ArrayList<Object> mocks) {
shivanisky marked this conversation as resolved.
Show resolved Hide resolved
if (!mocks.isEmpty()) {
StringBuilder sb = new StringBuilder(VERIFY_NO_INTERACTIONS_TEMPLATE_PREFIX);
mocks.forEach(mock -> sb.append(ANY_TEMPLATE_FIELD).append(",")); // verifyNoMoreInteractions(mock1, mock2 ...
Expand All @@ -257,6 +267,21 @@ private void rewriteFullVerify(List<Object> mocks) {
}
}

private void rewriteInOrderVerify(ArrayList<Object> mocks) {
shivanisky marked this conversation as resolved.
Show resolved Hide resolved
if (!mocks.isEmpty()) {
StringBuilder sb = new StringBuilder(VERIFY_IN_ORDER_TEMPLATE_PREFIX);
mocks.forEach(mock -> sb.append(ANY_TEMPLATE_FIELD).append(", ")); // InOrder inOrder = inOrder(mock1, mock2 ...
sb.delete(sb.length() - 2, sb.length());
sb.append(");");
rewriteTemplate(sb.toString(), mocks, nextStatementCoordinates);
if (!this.rewriteFailed) {
setNextStatementCoordinates(++numStatementsAdded);
visitor.maybeAddImport(MOCKITO_IMPORT_FQN_PREFX, "inOrder", false);
visitor.maybeAddImport(IN_ORDER_IMPORT_FQN);
}
}
}

private void setNextStatementCoordinates(int numStatementsAdded) {
if (numStatementsAdded <= 0 && bodyStatementIndex == 0) {
nextStatementCoordinates = methodBody.getCoordinates().firstStatement();
Expand All @@ -280,6 +305,7 @@ private void rewriteTemplate(String template, List<Object> templateParams, JavaC
methodBody = JavaTemplate.builder(template)
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "mockito-core-3.12"))
.staticImports("org.mockito.Mockito.*")
.imports(IN_ORDER_IMPORT_FQN)
.build()
.apply(
new Cursor(visitor.getCursor(), methodBody),
Expand Down Expand Up @@ -335,8 +361,12 @@ private static void appendToTemplate(StringBuilder templateBuilder, boolean buil
templateBuilder.append(templateField);
}

private static String getVerifyTemplate(List<Expression> arguments, String verificationMode, List<Object> templateParams) {
StringBuilder templateBuilder = new StringBuilder(VERIFY_TEMPLATE_PREFIX); // eg verify(object
private String getVerifyTemplate(List<Expression> arguments, String verificationMode, List<Object> templateParams) {
StringBuilder templateBuilder = new StringBuilder();
if (isVerificationsInOrder()) {
templateBuilder.append("inOrder.");
}
templateBuilder.append(VERIFY_TEMPLATE_PREFIX); // eg verify(object
if (!verificationMode.isEmpty()) {
templateBuilder.append(", ").append(verificationMode).append("(#{any(int)})"); // eg verify(object, times(2)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -68,15 +69,18 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration methodDecl
SetupStatementsRewriter ssr = new SetupStatementsRewriter(this, md.getBody());
J.Block methodBody = ssr.rewriteMethodBody();
List<Statement> statements = methodBody.getStatements();
List<JMockitBlockType> blockTypes = new ArrayList<>();

int bodyStatementIndex = 0;
// iterate over each statement in the method body, find Expectations blocks and rewrite them
while (bodyStatementIndex < statements.size()) {
Statement s = statements.get(bodyStatementIndex);
Optional<JMockitBlockType> blockType = JMockitUtils.getJMockitBlock(s);
if (blockType.isPresent()) {
Optional<JMockitBlockType> blockTypeOpt = JMockitUtils.getJMockitBlock(s);
if (blockTypeOpt.isPresent()) {
JMockitBlockType blockType = blockTypeOpt.get();
blockTypes.add(blockType);
JMockitBlockRewriter blockRewriter = new JMockitBlockRewriter(this, ctx, methodBody,
((J.NewClass) s), bodyStatementIndex, blockType.get());
((J.NewClass) s), bodyStatementIndex, blockType, blockTypes);
methodBody = blockRewriter.rewriteMethodBody();
statements = methodBody.getStatements();
// if the expectations rewrite failed, skip the next statement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ enum JMockitBlockType {
Expectations,
NonStrictExpectations,
Verifications,
VerificationsInOrder,
FullVerifications;

private final String fqn = "mockit." + this.name();

boolean isVerifications() {
return this == Verifications || this == FullVerifications;
return this == Verifications || this == FullVerifications || this == VerificationsInOrder;
}

static String getSupportedTypesStr() {
Expand Down
Loading