Skip to content

Commit

Permalink
Verify additional escapes (#44)
Browse files Browse the repository at this point in the history
* Verify additional escapes

* Extract common methods to compile per test class

* Remove JetBrains annotation
  • Loading branch information
timtebeek authored Dec 16, 2023
1 parent 80cdb8c commit 368f8b4
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,19 @@

import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.Compiler.javac;
import static org.junit.jupiter.api.Assertions.assertEquals;

class RefasterTemplateProcessorTest {
@ParameterizedTest
@ValueSource(strings = {
"ConstantsFormat",
"MethodThrows",
"NestedPreconditions",
"ParameterReuse",
"UseStringIsEmpty",
"SimplifyBooleans",
})
void generateRecipe(String recipeName) {
// As per https://github.com/google/compile-testing/blob/v0.21.0/src/main/java/com/google/testing/compile/package-info.java#L53-L55
Compilation compilation = javac()
.withProcessors(new RefasterTemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource("refaster/" + recipeName + ".java"));
Compilation compilation = compile("refaster/" + recipeName + ".java");
assertThat(compilation).succeeded();
assertThat(compilation).hadNoteCount(0);
assertThat(compilation)
Expand All @@ -59,34 +55,37 @@ void generateRecipe(String recipeName) {
"OrElseGetGet",
"RefasterAnyOf",
})
void skipRecipeGeneration(String recipeName){
Compilation compilation = javac()
.withProcessors(new RefasterTemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource("refaster/" + recipeName + ".java"));
void skipRecipeGeneration(String recipeName) {
Compilation compilation = compile("refaster/" + recipeName + ".java");
assertThat(compilation).succeeded();
assert compilation.generatedSourceFiles().isEmpty();
assertEquals(0, compilation.generatedSourceFiles().size(), "Should not generate recipe for " + recipeName);
}

@ParameterizedTest
@ValueSource(strings = {
"ShouldSupportNestedClasses",
"ShouldAddImports",
"MultipleDereferences",
"Escapes",
"Matching",
"MultipleDereferences",
"ShouldAddImports",
"ShouldSupportNestedClasses",
})
void nestedRecipes(String recipeName) {
Compilation compilation = javac()
.withProcessors(new RefasterTemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource("refaster/" + recipeName + ".java"));
Compilation compilation = compile("refaster/" + recipeName + ".java");
assertThat(compilation).succeeded();
assertThat(compilation).hadNoteCount(0);
assertThat(compilation) // Recipes (plural)
.generatedSourceFile("foo/" + recipeName + "Recipes")
.hasSourceEquivalentTo(JavaFileObjects.forResource("refaster/" + recipeName + "Recipes.java"));
}

private static Compilation compile(String resourceName) {
// As per https://github.com/google/compile-testing/blob/v0.21.0/src/main/java/com/google/testing/compile/package-info.java#L53-L55
return javac()
.withProcessors(new RefasterTemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource(resourceName));
}

static Collection<File> classpath() {
return Arrays.asList(
fileForClass(BeforeTemplate.class),
Expand All @@ -100,7 +99,7 @@ static Collection<File> classpath() {
}

// As per https://github.com/google/auto/blob/auto-value-1.10.2/factory/src/test/java/com/google/auto/factory/processor/AutoFactoryProcessorTest.java#L99
static File fileForClass(Class<?> c) {
private static File fileForClass(Class<?> c) {
URL url = c.getProtectionDomain().getCodeSource().getLocation();
assert url.getProtocol().equals("file") || url.getProtocol().equals("jrt") : "Unexpected URL: " + url;
return new File(url.getPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,8 @@ class TemplateProcessorTest {
})
void qualification(String qualifier) {
// As per https://github.com/google/compile-testing/blob/v0.21.0/src/main/java/com/google/testing/compile/package-info.java#L53-L55
Compilation compilation = javac()
.withProcessors(new RefasterTemplateProcessor(), new TemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource("template/ShouldAddClasspath.java"));
Compilation compilation = compile("template/ShouldAddClasspath.java");
assertThat(compilation).succeeded();
compilation.generatedSourceFiles().forEach(System.out::println);
assertThat(compilation)
.generatedSourceFile("foo/ShouldAddClasspathRecipes$" + qualifier + "Recipe$1_before")
.hasSourceEquivalentTo(JavaFileObjects.forResource("template/ShouldAddClasspathRecipe$" + qualifier + "Recipe$1_before.java"));
Expand All @@ -53,14 +49,17 @@ void qualification(String qualifier) {

@Test
void parameterReuse() {
Compilation compilation = javac()
.withProcessors(new RefasterTemplateProcessor(), new TemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource("template/ParameterReuse.java"));
Compilation compilation = compile("template/ParameterReuse.java");
assertThat(compilation).succeeded();
compilation.generatedSourceFiles().forEach(System.out::println);
assertThat(compilation)
.generatedSourceFile("foo/ParameterReuseRecipe$1_before")
.hasSourceEquivalentTo(JavaFileObjects.forResource("template/ParameterReuseRecipe$1_before.java"));
}

private static Compilation compile(String resourceName) {
return javac()
.withProcessors(new RefasterTemplateProcessor(), new TemplateProcessor())
.withClasspath(classpath())
.compile(JavaFileObjects.forResource(resourceName));
}
}
83 changes: 0 additions & 83 deletions src/test/resources/refaster/ConstantsFormatRecipe.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,28 @@
import com.sun.tools.javac.util.Constants;
import com.sun.tools.javac.util.Convert;

class ConstantsFormat {
@BeforeTemplate
String before(String value) {
return String.format("\"%s\"", Convert.quote(value));
public class Escapes {
public static class ConstantsFormat {
@BeforeTemplate
String before(String value) {
return String.format("\"%s\"", Convert.quote(value));
}

@AfterTemplate
String after(String value) {
return Constants.format(value);
}
}

@AfterTemplate
String after(String value) {
return Constants.format(value);
public static class Split {
@BeforeTemplate
String[] before(String s) {
return s.split("[^\\S]+");
}

@AfterTemplate
String[] after(String s) {
return s.split("\\s+");
}
}
}
145 changes: 145 additions & 0 deletions src/test/resources/refaster/EscapesRecipes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package foo;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.lang.NonNullApi;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.search.*;
import org.openrewrite.java.template.Primitive;
import org.openrewrite.java.template.Semantics;
import org.openrewrite.java.template.function.*;
import org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor;
import org.openrewrite.java.tree.*;

import java.util.*;

import static org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor.EmbeddingOption.*;

import com.sun.tools.javac.util.Convert;
import com.sun.tools.javac.util.Constants;

public class EscapesRecipes extends Recipe {
@Override
public String getDisplayName() {
return "`Escapes` Refaster recipes";
}

@Override
public String getDescription() {
return "Refaster template recipes for `foo.Escapes`.";
}

@Override
public List<Recipe> getRecipeList() {
return Arrays.asList(
new ConstantsFormatRecipe(),
new SplitRecipe()
);
}

@NonNullApi
public static class ConstantsFormatRecipe extends Recipe {

@Override
public String getDisplayName() {
return "Refaster template `Escapes.ConstantsFormat`";
}

@Override
public String getDescription() {
return "Recipe created for the following Refaster template:\n```java\npublic static class ConstantsFormat {\n \n @BeforeTemplate()\n String before(String value) {\n return String.format(\"\\\"%s\\\"\", Convert.quote(value));\n }\n \n @AfterTemplate()\n String after(String value) {\n return Constants.format(value);\n }\n}\n```\n.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
JavaVisitor<ExecutionContext> javaVisitor = new AbstractRefasterJavaVisitor() {
final JavaTemplate before = Semantics.expression(this, "before", (String value) -> String.format("\"%s\"", com.sun.tools.javac.util.Convert.quote(value))).build();
final JavaTemplate after = Semantics.expression(this, "after", (String value) -> com.sun.tools.javac.util.Constants.format(value)).build();

@Override
public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
JavaTemplate.Matcher matcher;
if ((matcher = before.matcher(getCursor())).find()) {
maybeRemoveImport("com.sun.tools.javac.util.Convert");
return embed(
after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
getCursor(),
ctx,
SHORTEN_NAMES
);
}
return super.visitMethodInvocation(elem, ctx);
}

};
return Preconditions.check(
Preconditions.and(
new UsesType<>("com.sun.tools.javac.util.Convert", true),
new UsesMethod<>("java.lang.String format(..)"),
new UsesMethod<>("com.sun.tools.javac.util.Convert quote(..)")
),
javaVisitor
);
}
}

@NonNullApi
public static class SplitRecipe extends Recipe {

@Override
public String getDisplayName() {
return "Refaster template `Escapes.Split`";
}

@Override
public String getDescription() {
return "Recipe created for the following Refaster template:\n```java\npublic static class Split {\n \n @BeforeTemplate()\n String[] before(String s) {\n return s.split(\"[^\\\\S]+\");\n }\n \n @AfterTemplate()\n String[] after(String s) {\n return s.split(\"\\\\s+\");\n }\n}\n```\n.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
JavaVisitor<ExecutionContext> javaVisitor = new AbstractRefasterJavaVisitor() {
final JavaTemplate before = Semantics.expression(this, "before", (String s) -> s.split("[^\\S]+")).build();
final JavaTemplate after = Semantics.expression(this, "after", (String s) -> s.split("\\s+")).build();

@Override
public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
JavaTemplate.Matcher matcher;
if ((matcher = before.matcher(getCursor())).find()) {
return embed(
after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
getCursor(),
ctx,
SHORTEN_NAMES
);
}
return super.visitMethodInvocation(elem, ctx);
}

};
return Preconditions.check(
new UsesMethod<>("java.lang.String split(..)"),
javaVisitor
);
}
}

}

0 comments on commit 368f8b4

Please sign in to comment.