Browse Source
This commit adds utilities that facilitate code generation patterns used by the AOT engine. Closes gh-28028pull/28041/head
7 changed files with 740 additions and 0 deletions
@ -0,0 +1,188 @@
@@ -0,0 +1,188 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.StringWriter; |
||||
import java.util.function.Consumer; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import javax.lang.model.element.Modifier; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
import org.springframework.javapoet.JavaFile; |
||||
import org.springframework.javapoet.MethodSpec; |
||||
import org.springframework.javapoet.TypeSpec; |
||||
|
||||
/** |
||||
* A code snippet using tabs indentation that is fully processed by JavaPoet so |
||||
* that imports are resolved. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 6.0 |
||||
*/ |
||||
public final class CodeSnippet { |
||||
|
||||
private static final String START_SNIPPET = "// start-snippet\n"; |
||||
|
||||
private static final String END_SNIPPET = "// end-snippet"; |
||||
|
||||
private final String fileContent; |
||||
|
||||
private final String snippet; |
||||
|
||||
|
||||
CodeSnippet(String fileContent, String snippet) { |
||||
this.fileContent = fileContent; |
||||
this.snippet = snippet; |
||||
} |
||||
|
||||
|
||||
String getFileContent() { |
||||
return this.fileContent; |
||||
} |
||||
|
||||
/** |
||||
* Return the rendered code snippet. |
||||
* @return a code snippet where imports have been resolved |
||||
*/ |
||||
public String getSnippet() { |
||||
return this.snippet; |
||||
} |
||||
|
||||
/** |
||||
* Specify if an import statement for the specified type is present. |
||||
* @param type the type to check |
||||
* @return true if this type has an import statement, false otherwise |
||||
*/ |
||||
public boolean hasImport(Class<?> type) { |
||||
return hasImport(type.getName()); |
||||
} |
||||
|
||||
/** |
||||
* Specify if an import statement for the specified class name is present. |
||||
* @param className the name of the class to check |
||||
* @return true if this type has an import statement, false otherwise |
||||
*/ |
||||
public boolean hasImport(String className) { |
||||
return getFileContent().lines().anyMatch(candidate -> |
||||
candidate.equals(String.format("import %s;", className))); |
||||
} |
||||
|
||||
/** |
||||
* Return a new {@link CodeSnippet} where the specified number of indentations |
||||
* have been removed. |
||||
* @param indent the number of indent to remove |
||||
* @return a CodeSnippet instance with the number of indentations removed |
||||
*/ |
||||
public CodeSnippet removeIndent(int indent) { |
||||
return new CodeSnippet(this.fileContent, this.snippet.lines().map(line -> |
||||
removeIndent(line, indent)).collect(Collectors.joining("\n"))); |
||||
} |
||||
|
||||
/** |
||||
* Create a {@link CodeSnippet} using the specified code. |
||||
* @param code the code snippet |
||||
* @return a {@link CodeSnippet} instance |
||||
*/ |
||||
public static CodeSnippet of(CodeBlock code) { |
||||
return new Builder().build(code); |
||||
} |
||||
|
||||
/** |
||||
* Process the specified code and return a fully-processed code snippet |
||||
* as a String. |
||||
* @param code a consumer to use to generate the code snippet |
||||
* @return a resolved code snippet |
||||
*/ |
||||
public static String process(Consumer<CodeBlock.Builder> code) { |
||||
CodeBlock.Builder body = CodeBlock.builder(); |
||||
code.accept(body); |
||||
return process(body.build()); |
||||
} |
||||
|
||||
/** |
||||
* Process the specified {@link CodeBlock code} and return a |
||||
* fully-processed code snippet as a String. |
||||
* @param code the code snippet |
||||
* @return a resolved code snippet |
||||
*/ |
||||
public static String process(CodeBlock code) { |
||||
return of(code).getSnippet(); |
||||
} |
||||
|
||||
private String removeIndent(String line, int indent) { |
||||
for (int i = 0; i < indent; i++) { |
||||
if (line.startsWith("\t")) { |
||||
line = line.substring(1); |
||||
} |
||||
} |
||||
return line; |
||||
} |
||||
|
||||
private static final class Builder { |
||||
|
||||
private static final String INDENT = "\t"; |
||||
|
||||
private static final String SNIPPET_INDENT = INDENT + INDENT; |
||||
|
||||
public CodeSnippet build(CodeBlock code) { |
||||
MethodSpec.Builder method = MethodSpec.methodBuilder("test") |
||||
.addModifiers(Modifier.PUBLIC); |
||||
CodeBlock.Builder body = CodeBlock.builder(); |
||||
body.add(START_SNIPPET); |
||||
body.add(code); |
||||
body.add(END_SNIPPET); |
||||
method.addCode(body.build()); |
||||
String fileContent = write(createTestJavaFile(method.build())); |
||||
String snippet = isolateGeneratedContent(fileContent); |
||||
return new CodeSnippet(fileContent, snippet); |
||||
} |
||||
|
||||
private String isolateGeneratedContent(String javaFile) { |
||||
int start = javaFile.indexOf(START_SNIPPET); |
||||
String tmp = javaFile.substring(start + START_SNIPPET.length()); |
||||
int end = tmp.indexOf(END_SNIPPET); |
||||
tmp = tmp.substring(0, end); |
||||
// Remove indent
|
||||
return tmp.lines().map(line -> { |
||||
if (!line.startsWith(SNIPPET_INDENT)) { |
||||
throw new IllegalStateException("Missing indent for " + line); |
||||
} |
||||
return line.substring(SNIPPET_INDENT.length()); |
||||
}).collect(Collectors.joining("\n")); |
||||
} |
||||
|
||||
private JavaFile createTestJavaFile(MethodSpec method) { |
||||
return JavaFile.builder("example", TypeSpec.classBuilder("Test") |
||||
.addModifiers(Modifier.PUBLIC) |
||||
.addMethod(method).build()).indent(INDENT).build(); |
||||
} |
||||
|
||||
private String write(JavaFile file) { |
||||
try { |
||||
StringWriter out = new StringWriter(); |
||||
file.writeTo(out); |
||||
return out.toString(); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new IllegalStateException("Failed to write " + file, ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
import org.springframework.javapoet.CodeBlock.Builder; |
||||
|
||||
|
||||
/** |
||||
* A {@link CodeBlock} wrapper for joining multiple blocks. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 6.0 |
||||
*/ |
||||
public class MultiCodeBlock { |
||||
|
||||
private final List<CodeBlock> codeBlocks = new ArrayList<>(); |
||||
|
||||
|
||||
/** |
||||
* Add the specified {@link CodeBlock}. |
||||
* @param code the code block to add |
||||
*/ |
||||
public void add(CodeBlock code) { |
||||
if (code.isEmpty()) { |
||||
throw new IllegalArgumentException("Could not add empty CodeBlock"); |
||||
} |
||||
this.codeBlocks.add(code); |
||||
} |
||||
|
||||
/** |
||||
* Add a {@link CodeBlock} using the specified callback. |
||||
* @param code the callback to use |
||||
*/ |
||||
public void add(Consumer<Builder> code) { |
||||
Builder builder = CodeBlock.builder(); |
||||
code.accept(builder); |
||||
add(builder.build()); |
||||
} |
||||
|
||||
/** |
||||
* Add a code block using the specified formatted String and the specified |
||||
* arguments. |
||||
* @param code the code |
||||
* @param arguments the arguments |
||||
* @see Builder#add(String, Object...) |
||||
*/ |
||||
public void add(String code, Object... arguments) { |
||||
add(CodeBlock.of(code, arguments)); |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link CodeBlock} that joins the different blocks registered in |
||||
* this instance with the specified delimiter. |
||||
* @param delimiter the delimiter to use (not {@literal null}) |
||||
* @return a {@link CodeBlock} joining the blocks of this instance with the |
||||
* specified {@code delimiter} |
||||
* @see CodeBlock#join(Iterable, String) |
||||
*/ |
||||
public CodeBlock join(String delimiter) { |
||||
return CodeBlock.join(this.codeBlocks, delimiter); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,194 @@
@@ -0,0 +1,194 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.function.Consumer; |
||||
import java.util.function.Function; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
import org.springframework.javapoet.CodeBlock.Builder; |
||||
|
||||
|
||||
/** |
||||
* A {@link CodeBlock} wrapper for multiple statements. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @since 6.0 |
||||
*/ |
||||
public final class MultiStatement { |
||||
|
||||
private final List<Statement> statements = new ArrayList<>(); |
||||
|
||||
|
||||
/** |
||||
* Specify if this instance is empty. |
||||
* @return {@code true} if no statement is registered, {@code false} otherwise |
||||
*/ |
||||
public boolean isEmpty() { |
||||
return this.statements.isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* Add the specified {@link CodeBlock codeblock} rendered as-is. |
||||
* @param codeBlock the code block to add |
||||
* @see #addStatement(CodeBlock) to add a code block that represents |
||||
* a statement |
||||
*/ |
||||
public void add(CodeBlock codeBlock) { |
||||
this.statements.add(Statement.of(codeBlock)); |
||||
} |
||||
|
||||
/** |
||||
* Add a {@link CodeBlock} rendered as-is using the specified callback. |
||||
* @param code the callback to use |
||||
* @see #addStatement(CodeBlock) to add a code block that represents |
||||
* a statement |
||||
*/ |
||||
public void add(Consumer<Builder> code) { |
||||
CodeBlock.Builder builder = CodeBlock.builder(); |
||||
code.accept(builder); |
||||
add(builder.build()); |
||||
} |
||||
|
||||
/** |
||||
* Add a statement. |
||||
* @param statement the statement to add |
||||
*/ |
||||
public void addStatement(CodeBlock statement) { |
||||
this.statements.add(Statement.ofStatement(statement)); |
||||
} |
||||
|
||||
/** |
||||
* Add a statement using the specified callback. |
||||
* @param code the callback to use |
||||
*/ |
||||
public void addStatement(Consumer<Builder> code) { |
||||
CodeBlock.Builder builder = CodeBlock.builder(); |
||||
code.accept(builder); |
||||
addStatement(builder.build()); |
||||
} |
||||
|
||||
/** |
||||
* Add a statement using the specified formatted String and the specified |
||||
* arguments. |
||||
* @param code the code of the statement |
||||
* @param args the arguments for placeholders |
||||
* @see CodeBlock#of(String, Object...) |
||||
*/ |
||||
public void addStatement(String code, Object... args) { |
||||
addStatement(CodeBlock.of(code, args)); |
||||
} |
||||
|
||||
/** |
||||
* Add the statements produced from the {@code itemGenerator} applied on the specified |
||||
* items. |
||||
* @param items the items to handle, each item is represented as a statement |
||||
* @param itemGenerator the item generator |
||||
* @param <T> the type of the item |
||||
*/ |
||||
public <T> void addAll(Iterable<T> items, Function<T, CodeBlock> itemGenerator) { |
||||
items.forEach(element -> addStatement(itemGenerator.apply(element))); |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link CodeBlock} that applies all the {@code statements} of this |
||||
* instance. If only one statement is available, it is not completed using the |
||||
* {@code ;} termination so that it can be used in the context of a lambda. |
||||
* @return the statement(s) |
||||
*/ |
||||
public CodeBlock toCodeBlock() { |
||||
Builder code = CodeBlock.builder(); |
||||
for (int i = 0; i < this.statements.size(); i++) { |
||||
Statement statement = this.statements.get(i); |
||||
statement.contribute(code, this.isMulti(), i == this.statements.size() - 1); |
||||
} |
||||
return code.build(); |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link CodeBlock} that applies all the {@code statements} of this |
||||
* instance in the context of a lambda. |
||||
* @param lambda the context of the lambda, must end with {@code ->} |
||||
* @return the lambda body |
||||
*/ |
||||
public CodeBlock toCodeBlock(CodeBlock lambda) { |
||||
Builder code = CodeBlock.builder(); |
||||
code.add(lambda); |
||||
if (isMulti()) { |
||||
code.beginControlFlow(""); |
||||
} |
||||
else { |
||||
code.add(" "); |
||||
} |
||||
code.add(toCodeBlock()); |
||||
if (isMulti()) { |
||||
code.add("\n").unindent().add("}"); |
||||
} |
||||
return code.build(); |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link CodeBlock} that applies all the {@code statements} of this |
||||
* instance in the context of a lambda. |
||||
* @param lambda the context of the lambda, must end with {@code ->} |
||||
* @return the lambda body |
||||
*/ |
||||
public CodeBlock toCodeBlock(String lambda) { |
||||
return toCodeBlock(CodeBlock.of(lambda)); |
||||
} |
||||
|
||||
private boolean isMulti() { |
||||
return this.statements.size() > 1; |
||||
} |
||||
|
||||
|
||||
private static class Statement { |
||||
|
||||
private final CodeBlock codeBlock; |
||||
|
||||
private final boolean addStatementTermination; |
||||
|
||||
Statement(CodeBlock codeBlock, boolean addStatementTermination) { |
||||
this.codeBlock = codeBlock; |
||||
this.addStatementTermination = addStatementTermination; |
||||
} |
||||
|
||||
void contribute(CodeBlock.Builder code, boolean multi, boolean isLastStatement) { |
||||
code.add(this.codeBlock); |
||||
if (this.addStatementTermination) { |
||||
if (!isLastStatement) { |
||||
code.add(";\n"); |
||||
} |
||||
else if (multi) { |
||||
code.add(";"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static Statement ofStatement(CodeBlock codeBlock) { |
||||
return new Statement(codeBlock, true); |
||||
} |
||||
|
||||
static Statement of(CodeBlock codeBlock) { |
||||
return new Statement(codeBlock, false); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
/** |
||||
* Support classes for JavaPoet usage. |
||||
*/ |
||||
@NonNullApi |
||||
@NonNullFields |
||||
package org.springframework.javapoet.support; |
||||
|
||||
import org.springframework.lang.NonNullApi; |
||||
import org.springframework.lang.NonNullFields; |
||||
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link CodeSnippet}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class CodeSnippetTests { |
||||
|
||||
@Test |
||||
void snippetUsesTabs() { |
||||
CodeBlock.Builder code = CodeBlock.builder(); |
||||
code.beginControlFlow("if (condition)"); |
||||
code.addStatement("bean.doThis()"); |
||||
code.endControlFlow(); |
||||
CodeSnippet codeSnippet = CodeSnippet.of(code.build()); |
||||
assertThat(codeSnippet.getSnippet()).isEqualTo(""" |
||||
if (condition) { |
||||
bean.doThis(); |
||||
} |
||||
"""); |
||||
} |
||||
|
||||
@Test |
||||
void snippetResolvesImports() { |
||||
CodeSnippet codeSnippet = CodeSnippet.of( |
||||
CodeBlock.of("$T list = new $T<>()", List.class, ArrayList.class)); |
||||
assertThat(codeSnippet.getSnippet()).isEqualTo("List list = new ArrayList<>()"); |
||||
assertThat(codeSnippet.hasImport(List.class)).isTrue(); |
||||
assertThat(codeSnippet.hasImport(ArrayList.class)).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void removeIndent() { |
||||
CodeBlock.Builder code = CodeBlock.builder(); |
||||
code.beginControlFlow("if (condition)"); |
||||
code.addStatement("doStuff()"); |
||||
code.endControlFlow(); |
||||
CodeSnippet snippet = CodeSnippet.of(code.build()); |
||||
assertThat(snippet.getSnippet().lines()).contains("\tdoStuff();"); |
||||
assertThat(snippet.removeIndent(1).getSnippet().lines()).contains("doStuff();"); |
||||
} |
||||
|
||||
@Test |
||||
void processProvidesSnippet() { |
||||
assertThat(CodeSnippet.process(code -> code.add("$T list;", List.class))) |
||||
.isEqualTo("List list;"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; |
||||
|
||||
/** |
||||
* Tests for {@link MultiCodeBlock}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class MultiCodeBlockTests { |
||||
|
||||
@Test |
||||
void joinWithNoElement() { |
||||
MultiCodeBlock multi = new MultiCodeBlock(); |
||||
assertThat(multi.join(", ").isEmpty()).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void joinWithEmptyElement() { |
||||
MultiCodeBlock multi = new MultiCodeBlock(); |
||||
assertThatIllegalArgumentException().isThrownBy(() -> multi.add(CodeBlock.builder().build())); |
||||
} |
||||
|
||||
@Test |
||||
void joinWithSingleElement() { |
||||
MultiCodeBlock multi = new MultiCodeBlock(); |
||||
multi.add(CodeBlock.of("$S", "Hello")); |
||||
assertThat(multi.join(", ")).hasToString("\"Hello\""); |
||||
} |
||||
|
||||
@Test |
||||
void joinWithSeveralElement() { |
||||
MultiCodeBlock multi = new MultiCodeBlock(); |
||||
multi.add(CodeBlock.of("$S", "Hello")); |
||||
multi.add(code -> code.add("42")); |
||||
multi.add("null"); |
||||
assertThat(multi.join(", ")).hasToString("\"Hello\", 42, null"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,131 @@
@@ -0,0 +1,131 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* 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 org.springframework.javapoet.support; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.javapoet.CodeBlock; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link MultiStatement}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class MultiStatementTests { |
||||
|
||||
@Test |
||||
void isEmptyWithNoStatement() { |
||||
assertThat(new MultiStatement().isEmpty()).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void isEmptyWithStatement() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement(CodeBlock.of("int i = 0")); |
||||
assertThat(statements.isEmpty()).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void singleStatement() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement("field.method($S)", "hello"); |
||||
CodeBlock codeBlock = statements.toCodeBlock(); |
||||
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")"); |
||||
} |
||||
|
||||
@Test |
||||
void singleStatementWithCallback() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement(code -> code.add("field.method($S)", "hello")); |
||||
CodeBlock codeBlock = statements.toCodeBlock(); |
||||
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")"); |
||||
} |
||||
|
||||
@Test |
||||
void singleStatementWithCodeBlock() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement(CodeBlock.of("field.method($S)", "hello")); |
||||
CodeBlock codeBlock = statements.toCodeBlock(); |
||||
assertThat(codeBlock.toString()).isEqualTo("field.method(\"hello\")"); |
||||
} |
||||
|
||||
@Test |
||||
void multiStatements() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement("field.method($S)", "hello"); |
||||
statements.addStatement("field.anotherMethod($S)", "hello"); |
||||
CodeBlock codeBlock = statements.toCodeBlock(); |
||||
assertThat(codeBlock.toString()).isEqualTo(""" |
||||
field.method("hello"); |
||||
field.anotherMethod("hello");"""); |
||||
} |
||||
|
||||
@Test |
||||
void multiStatementsWithCodeBlockRenderedAsIs() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement("field.method($S)", "hello"); |
||||
statements.add(CodeBlock.of(("// Hello\n"))); |
||||
statements.add(code -> code.add("// World\n")); |
||||
statements.addStatement("field.anotherMethod($S)", "hello"); |
||||
CodeBlock codeBlock = statements.toCodeBlock(); |
||||
assertThat(codeBlock.toString()).isEqualTo(""" |
||||
field.method("hello"); |
||||
// Hello
|
||||
// World
|
||||
field.anotherMethod("hello");"""); |
||||
} |
||||
|
||||
@Test |
||||
void singleStatementWithLambda() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement("field.method($S)", "hello"); |
||||
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->")); |
||||
assertThat(codeBlock.toString()).isEqualTo("() -> field.method(\"hello\")"); |
||||
} |
||||
|
||||
@Test |
||||
void multiStatementsWithLambda() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addStatement("field.method($S)", "hello"); |
||||
statements.addStatement("field.anotherMethod($S)", "hello"); |
||||
CodeBlock codeBlock = statements.toCodeBlock(CodeBlock.of("() ->")); |
||||
assertThat(codeBlock.toString().lines()).containsExactly( |
||||
"() -> {", |
||||
" field.method(\"hello\");", |
||||
" field.anotherMethod(\"hello\");", |
||||
"}"); |
||||
} |
||||
|
||||
@Test |
||||
void multiStatementsWithAddAll() { |
||||
MultiStatement statements = new MultiStatement(); |
||||
statements.addAll(List.of(0, 1, 2), |
||||
index -> CodeBlock.of("field[$L] = $S", index, "hello")); |
||||
CodeBlock codeBlock = statements.toCodeBlock("() ->"); |
||||
assertThat(codeBlock.toString().lines()).containsExactly( |
||||
"() -> {", |
||||
" field[0] = \"hello\";", |
||||
" field[1] = \"hello\";", |
||||
" field[2] = \"hello\";", |
||||
"}"); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue