Add module to support testing of generated code

Add a new unpublished `spring-core-test` module to support testing of
generated code. The module include a `TestCompiler` class which can be
used to dynamically compile generated Java code. It also include an
AssertJ friendly `SourceFile` class which uses qdox to provide targeted
assertions on specific parts of a generated source file.

See gh-28120
This commit is contained in:
Phillip Webb
2022-02-24 21:57:11 -08:00
committed by Stephane Nicoll
parent b5695b9248
commit 653dc5951d
34 changed files with 3163 additions and 1 deletions

View File

@@ -0,0 +1,38 @@
/*
* 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.aot.test.generator.compile;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link CompilationException}.
*
* @author Phillip Webb
* @since 6.0
*/
class CompilationExceptionTests {
@Test
void getMessageReturnsMessage() {
CompilationException exception = new CompilationException("message");
assertThat(exception).hasMessage("message");
}
}

View File

@@ -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.aot.test.generator.compile;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.aot.test.generator.file.ResourceFile;
import org.springframework.aot.test.generator.file.ResourceFiles;
import org.springframework.aot.test.generator.file.SourceFile;
import org.springframework.aot.test.generator.file.SourceFiles;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link Compiled}.
*
* @author Phillip Webb
* @since 6.0
*/
class CompiledTests {
private static final String HELLO_WORLD = """
package com.example;
public class HelloWorld implements java.util.function.Supplier<String> {
public String get() {
return "Hello World!";
}
}
""";
private static final String HELLO_SPRING = """
package com.example;
public class HelloSpring implements java.util.function.Supplier<String> {
public String get() {
return "Hello Spring!"; // !!
}
}
""";
@Test
void getSourceFileWhenSingleReturnsSourceFile() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
TestCompiler.forSystem().compile(sourceFile,
compiled -> assertThat(compiled.getSourceFile()).isSameAs(sourceFile));
}
@Test
void getSourceFileWhenMultipleThrowsException() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD),
SourceFile.of(HELLO_SPRING));
TestCompiler.forSystem().compile(sourceFiles,
compiled -> assertThatIllegalStateException().isThrownBy(
compiled::getSourceFile));
}
@Test
void getSourceFileWhenNoneThrowsException() {
TestCompiler.forSystem().compile(
compiled -> assertThatIllegalStateException().isThrownBy(
compiled::getSourceFile));
}
@Test
void getSourceFilesReturnsSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD),
SourceFile.of(HELLO_SPRING));
TestCompiler.forSystem().compile(sourceFiles,
compiled -> assertThat(compiled.getSourceFiles()).isEqualTo(sourceFiles));
}
@Test
void getResourceFileWhenSingleReturnsSourceFile() {
ResourceFile resourceFile = ResourceFile.of("META-INF/myfile", "test");
TestCompiler.forSystem().withResources(resourceFile).compile(
compiled -> assertThat(compiled.getResourceFile()).isSameAs(
resourceFile));
}
@Test
void getResourceFileWhenMultipleThrowsException() {
ResourceFiles resourceFiles = ResourceFiles.of(
ResourceFile.of("META-INF/myfile1", "test1"),
ResourceFile.of("META-INF/myfile2", "test2"));
TestCompiler.forSystem().withResources(resourceFiles).compile(
compiled -> assertThatIllegalStateException().isThrownBy(
() -> compiled.getResourceFile()));
}
@Test
void getResourceFileWhenNoneThrowsException() {
TestCompiler.forSystem().compile(
compiled -> assertThatIllegalStateException().isThrownBy(
() -> compiled.getResourceFile()));
}
@Test
void getResourceFilesReturnsResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(
ResourceFile.of("META-INF/myfile1", "test1"),
ResourceFile.of("META-INF/myfile2", "test2"));
TestCompiler.forSystem().withResources(resourceFiles).compile(
compiled -> assertThat(compiled.getResourceFiles()).isEqualTo(
resourceFiles));
}
@Test
void getInstanceWhenNoneMatchesThrowsException() {
TestCompiler.forSystem().compile(SourceFile.of(HELLO_WORLD),
compiled -> assertThatIllegalStateException().isThrownBy(
() -> compiled.getInstance(Callable.class)));
}
@Test
void getInstanceWhenMultipleMatchesThrowsException() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD),
SourceFile.of(HELLO_SPRING));
TestCompiler.forSystem().compile(sourceFiles,
compiled -> assertThatIllegalStateException().isThrownBy(
() -> compiled.getInstance(Supplier.class)));
}
@Test
void getInstanceWhenNoDefaultConstructorThrowsException() {
SourceFile sourceFile = SourceFile.of("""
package com.example;
public class HelloWorld implements java.util.function.Supplier<String> {
public HelloWorld(String name) {
}
public String get() {
return "Hello World!";
}
}
""");
TestCompiler.forSystem().compile(sourceFile,
compiled -> assertThatIllegalStateException().isThrownBy(
() -> compiled.getInstance(Supplier.class)));
}
@Test
void getInstanceReturnsInstance() {
TestCompiler.forSystem().compile(SourceFile.of(HELLO_WORLD),
compiled -> assertThat(compiled.getInstance(Supplier.class)).isNotNull());
}
@Test
void getInstanceByNameReturnsInstance() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD),
SourceFile.of(HELLO_SPRING));
TestCompiler.forSystem().compile(sourceFiles,
compiled -> assertThat(compiled.getInstance(Supplier.class,
"com.example.HelloWorld")).isNotNull());
}
@Test
void getAllCompiledClassesReturnsCompiledClasses() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD),
SourceFile.of(HELLO_SPRING));
TestCompiler.forSystem().compile(sourceFiles, compiled -> {
List<Class<?>> classes = compiled.getAllCompiledClasses();
assertThat(classes.stream().map(Class::getName)).containsExactlyInAnyOrder(
"com.example.HelloWorld", "com.example.HelloSpring");
});
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.aot.test.generator.compile;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import javax.tools.JavaFileObject.Kind;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DynamicClassFileObject}.
*
* @author Phillip Webb
* @since 6.0
*/
class DynamicClassFileObjectTests {
@Test
void getUriReturnsGeneratedUriBasedOnClassName() {
DynamicClassFileObject fileObject = new DynamicClassFileObject(
"com.example.MyClass");
assertThat(fileObject.toUri()).hasToString("class:///com/example/MyClass.class");
}
@Test
void getKindReturnsClass() {
DynamicClassFileObject fileObject = new DynamicClassFileObject(
"com.example.MyClass");
assertThat(fileObject.getKind()).isEqualTo(Kind.CLASS);
}
@Test
void openOutputStreamWritesToBytes() throws Exception {
DynamicClassFileObject fileObject = new DynamicClassFileObject(
"com.example.MyClass");
try(OutputStream outputStream = fileObject.openOutputStream()) {
new ByteArrayInputStream("test".getBytes()).transferTo(outputStream);
}
assertThat(fileObject.getBytes()).isEqualTo("test".getBytes());
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.aot.test.generator.compile;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
/**
* Tests for {@link DynamicJavaFileManager}.
*
* @author Phillip Webb
* @since 6.0
*/
class DynamicJavaFileManagerTests {
@Mock
private JavaFileManager parentFileManager;
@Mock
private Location location;
private ClassLoader classLoader;
private DynamicJavaFileManager fileManager;
@BeforeEach
void setup() {
MockitoAnnotations.openMocks(this);
this.classLoader = new ClassLoader() {
};
this.fileManager = new DynamicJavaFileManager(this.parentFileManager,
this.classLoader);
}
@Test
void getClassLoaderReturnsClassLoader() {
assertThat(this.fileManager.getClassLoader(this.location)).isSameAs(
this.classLoader);
}
@Test
void getJavaFileForOutputWhenClassKindReturnsDynamicClassFile() throws Exception {
JavaFileObject fileObject = this.fileManager.getJavaFileForOutput(this.location,
"com.example.MyClass", Kind.CLASS, null);
assertThat(fileObject).isInstanceOf(DynamicClassFileObject.class);
}
@Test
void getJavaFileForOutputWhenClassKindAndAlreadySeenReturnsSameDynamicClassFile()
throws Exception {
JavaFileObject fileObject1 = this.fileManager.getJavaFileForOutput(this.location,
"com.example.MyClass", Kind.CLASS, null);
JavaFileObject fileObject2 = this.fileManager.getJavaFileForOutput(this.location,
"com.example.MyClass", Kind.CLASS, null);
assertThat(fileObject1).isSameAs(fileObject2);
}
@Test
void getJavaFileForOutputWhenNotClassKindDelegatesToParentFileManager()
throws Exception {
this.fileManager.getJavaFileForOutput(this.location, "com.example.MyClass",
Kind.SOURCE, null);
then(this.parentFileManager).should().getJavaFileForOutput(this.location,
"com.example.MyClass", Kind.SOURCE, null);
}
@Test
void getClassFilesReturnsClassFiles() throws Exception {
this.fileManager.getJavaFileForOutput(this.location, "com.example.MyClass1",
Kind.CLASS, null);
this.fileManager.getJavaFileForOutput(this.location, "com.example.MyClass2",
Kind.CLASS, null);
assertThat(this.fileManager.getClassFiles()).containsKeys("com.example.MyClass1",
"com.example.MyClass2");
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.aot.test.generator.compile;
import org.junit.jupiter.api.Test;
import org.springframework.aot.test.generator.file.SourceFile;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DynamicJavaFileObject}.
*
* @author Phillip Webb
* @since 6.0
*/
class DynamicJavaFileObjectTests {
private static final String CONTENT = "package com.example; public class Hello {}";
@Test
void getUriReturnsPath() {
DynamicJavaFileObject fileObject = new DynamicJavaFileObject(SourceFile.of(CONTENT));
assertThat(fileObject.toUri()).hasToString("com/example/Hello.java");
}
@Test
void getCharContentReturnsContent() throws Exception {
DynamicJavaFileObject fileObject = new DynamicJavaFileObject(SourceFile.of(CONTENT));
assertThat(fileObject.getCharContent(true)).isEqualTo(CONTENT);
}
}

View File

@@ -0,0 +1,179 @@
/*
* 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.aot.test.generator.compile;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import org.springframework.aot.test.generator.file.ResourceFile;
import org.springframework.aot.test.generator.file.ResourceFiles;
import org.springframework.aot.test.generator.file.SourceFile;
import org.springframework.aot.test.generator.file.SourceFiles;
import org.springframework.aot.test.generator.file.WritableContent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link TestCompiler}.
*
* @author Phillip Webb
*/
class TestCompilerTests {
private static final String HELLO_WORLD = """
package com.example;
import java.util.function.Supplier;
@Deprecated
public class Hello implements Supplier<String> {
public String get() {
return "Hello World!";
}
}
""";
private static final String HELLO_SPRING = """
package com.example;
import java.util.function.Supplier;
public class Hello implements Supplier<String> {
public String get() {
return "Hello Spring!"; // !!
}
}
""";
private static final String HELLO_BAD = """
package com.example;
public class Hello implements Supplier<String> {
public String get() {
return "Missing Import!";
}
}
""";
@Test
@SuppressWarnings("unchecked")
void compileWhenHasDifferentClassesWithSameClassNameCompilesBoth() {
TestCompiler.forSystem().withSources(SourceFile.of(HELLO_WORLD)).compile(
compiled -> {
Supplier<String> supplier = compiled.getInstance(Supplier.class,
"com.example.Hello");
assertThat(supplier.get()).isEqualTo("Hello World!");
});
TestCompiler.forSystem().withSources(SourceFile.of(HELLO_SPRING)).compile(
compiled -> {
Supplier<String> supplier = compiled.getInstance(Supplier.class,
"com.example.Hello");
assertThat(supplier.get()).isEqualTo("Hello Spring!");
});
}
@Test
void compileAndGetSourceFile() {
TestCompiler.forSystem().withSources(SourceFile.of(HELLO_SPRING)).compile(
compiled -> assertThat(compiled.getSourceFile()).hasMethodNamed(
"get").withBodyContaining("// !!"));
}
@Test
void compileWhenSourceHasCompileErrors() {
assertThatExceptionOfType(CompilationException.class).isThrownBy(
() -> TestCompiler.forSystem().withSources(
SourceFile.of(HELLO_BAD)).compile(compiled -> {
}));
}
@Test
void withSourcesArrayAddsSource() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
TestCompiler.forSystem().withSources(sourceFile).compile(
this::assertSuppliesHelloWorld);
}
@Test
void withSourcesAddsSource() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD));
TestCompiler.forSystem().withSources(sourceFiles).compile(
this::assertSuppliesHelloWorld);
}
@Test
void withResourcesArrayAddsResource() {
ResourceFile resourceFile = ResourceFile.of("META-INF/myfile", "test");
TestCompiler.forSystem().withResources(resourceFile).compile(
this::assertHasResource);
}
@Test
void withResourcesAddsResource() {
ResourceFiles resourceFiles = ResourceFiles.of(
ResourceFile.of("META-INF/myfile", "test"));
TestCompiler.forSystem().withResources(resourceFiles).compile(
this::assertHasResource);
}
@Test
void compileWithWritableContent() {
WritableContent content = appendable -> appendable.append(HELLO_WORLD);
TestCompiler.forSystem().compile(content, this::assertSuppliesHelloWorld);
}
@Test
void compileWithSourceFile() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
TestCompiler.forSystem().compile(sourceFile, this::assertSuppliesHelloWorld);
}
@Test
void compileWithSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD));
TestCompiler.forSystem().compile(sourceFiles, this::assertSuppliesHelloWorld);
}
@Test
void compileWithSourceFilesAndResourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SourceFile.of(HELLO_WORLD));
ResourceFiles resourceFiles = ResourceFiles.of(
ResourceFile.of("META-INF/myfile", "test"));
TestCompiler.forSystem().compile(sourceFiles, resourceFiles, compiled -> {
assertSuppliesHelloWorld(compiled);
assertHasResource(compiled);
});
}
private void assertSuppliesHelloWorld(Compiled compiled) {
assertThat(compiled.getInstance(Supplier.class).get()).isEqualTo("Hello World!");
}
private void assertHasResource(Compiled compiled) {
assertThat(compiled.getClassLoader().getResourceAsStream(
"META-INF/myfile")).hasContent("test");
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.aot.test.generator.file;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link MethodAssert}.
*
* @author Phillip Webb
*/
class MethodAssertTests {
private static final String SAMPLE = """
package com.example;
public class Sample {
public void run() {
System.out.println("Hello World!");
}
}
""";
private final SourceFile sourceFile = SourceFile.of(SAMPLE);
@Test
void withBodyWhenMatches() {
assertThat(this.sourceFile).hasMethodNamed("run").withBody("""
System.out.println("Hello World!");""");
}
@Test
void withBodyWhenDoesNotMatchThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).hasMethodNamed("run").withBody("""
System.out.println("Hello Spring!");""")).withMessageContaining(
"to be equal to");
}
@Test
void withBodyContainingWhenContainsAll() {
assertThat(this.sourceFile).hasMethodNamed("run").withBodyContaining("Hello",
"World!");
}
@Test
void withBodyWhenDoesNotContainOneThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).hasMethodNamed(
"run").withBodyContaining("Hello",
"Spring!")).withMessageContaining("to contain");
}
}

View File

@@ -0,0 +1,52 @@
/*
* 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.aot.test.generator.file;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ResourceFile}.
*
* @author Phillip Webb
* @since 6.0
*/
class ResourceFileTests {
@Test
void ofPathAndCharSequenceCreatesResource() {
ResourceFile file = ResourceFile.of("path", "test");
assertThat(file.getPath()).isEqualTo("path");
assertThat(file.getContent()).isEqualTo("test");
}
@Test
void ofPathAndWritableContentCreatesResource() {
ResourceFile file = ResourceFile.of("path", appendable -> appendable.append("test"));
assertThat(file.getPath()).isEqualTo("path");
assertThat(file.getContent()).isEqualTo("test");
}
@Test
@SuppressWarnings("deprecation")
void assertThatReturnsResourceFileAssert() {
ResourceFile file = ResourceFile.of("path", "test");
assertThat(file.assertThat()).isInstanceOf(ResourceFileAssert.class);
}
}

View File

@@ -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.aot.test.generator.file;
import java.util.Iterator;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatObject;
class ReResourceFilesTests {
private static final ResourceFile RESOURCE_FILE_1 = ResourceFile.of("path1",
"resource1");
private static final ResourceFile RESOURCE_FILE_2 = ResourceFile.of("path2",
"resource2");
@Test
void noneReturnsNone() {
ResourceFiles none = ResourceFiles.none();
assertThat(none).isNotNull();
assertThat(none.isEmpty()).isTrue();
}
@Test
void ofCreatesResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
assertThat(resourceFiles).containsExactly(RESOURCE_FILE_1, RESOURCE_FILE_2);
}
@Test
void andAddsResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1);
ResourceFiles added = resourceFiles.and(RESOURCE_FILE_2);
assertThat(resourceFiles).containsExactly(RESOURCE_FILE_1);
assertThat(added).containsExactly(RESOURCE_FILE_1, RESOURCE_FILE_2);
}
@Test
void andResourceFilesAddsResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1);
ResourceFiles added = resourceFiles.and(ResourceFiles.of(RESOURCE_FILE_2));
assertThat(resourceFiles).containsExactly(RESOURCE_FILE_1);
assertThat(added).containsExactly(RESOURCE_FILE_1, RESOURCE_FILE_2);
}
@Test
void iteratorIteratesResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
Iterator<ResourceFile> iterator = resourceFiles.iterator();
assertThat(iterator.next()).isEqualTo(RESOURCE_FILE_1);
assertThat(iterator.next()).isEqualTo(RESOURCE_FILE_2);
assertThat(iterator.hasNext()).isFalse();
}
@Test
void streamStreamsResourceFiles() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
assertThat(resourceFiles.stream()).containsExactly(RESOURCE_FILE_1,
RESOURCE_FILE_2);
}
@Test
void isEmptyWhenEmptyReturnsTrue() {
ResourceFiles resourceFiles = ResourceFiles.of();
assertThat(resourceFiles.isEmpty()).isTrue();
}
@Test
void isEmptyWhenNotEmptyReturnsFalse() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1);
assertThat(resourceFiles.isEmpty()).isFalse();
}
@Test
void getWhenHasFileReturnsFile() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1);
assertThat(resourceFiles.get("path1")).isNotNull();
}
@Test
void getWhenMissingFileReturnsNull() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_2);
assertThatObject(resourceFiles.get("path1")).isNull();
}
@Test
void getSingleWhenHasNoFilesThrowsException() {
assertThatIllegalStateException().isThrownBy(
() -> ResourceFiles.none().getSingle());
}
@Test
void getSingleWhenHasMultipleFilesThrowsException() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
assertThatIllegalStateException().isThrownBy(() -> resourceFiles.getSingle());
}
@Test
void getSingleWhenHasSingleFileReturnsFile() {
ResourceFiles resourceFiles = ResourceFiles.of(RESOURCE_FILE_1);
assertThat(resourceFiles.getSingle()).isEqualTo(RESOURCE_FILE_1);
}
@Test
void equalsAndHashCode() {
ResourceFiles s1 = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
ResourceFiles s2 = ResourceFiles.of(RESOURCE_FILE_1, RESOURCE_FILE_2);
ResourceFiles s3 = ResourceFiles.of(RESOURCE_FILE_1);
assertThat(s1.hashCode()).isEqualTo(s2.hashCode());
assertThatObject(s1).isEqualTo(s2).isNotEqualTo(s3);
}
}

View File

@@ -0,0 +1,128 @@
/*
* 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.aot.test.generator.file;
import java.util.concurrent.Callable;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link SourceFileAssert}.
*
* @author Phillip Webb
*/
class SourceFileAssertTests {
private static final String SAMPLE = """
package com.example;
import java.lang.Runnable;
public class Sample implements Runnable {
void run() {
run("Hello World!");
}
void run(String message) {
System.out.println(message);
}
public static void main(String[] args) {
new Sample().run();
}
}
""";
private final SourceFile sourceFile = SourceFile.of(SAMPLE);
@Test
void containsWhenContainsAll() {
assertThat(this.sourceFile).contains("Sample", "main");
}
@Test
void containsWhenMissingOneThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).contains("Sample",
"missing")).withMessageContaining("to contain");
}
@Test
void isEqualToWhenEqual() {
assertThat(this.sourceFile).isEqualTo(SAMPLE);
}
@Test
void isEqualToWhenNotEqualThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).isEqualTo("no")).withMessageContaining(
"expected", "but was");
}
@Test
void implementsInterfaceWhenImplementsInterface() {
assertThat(this.sourceFile).implementsInterface(Runnable.class);
}
@Test
void implementsInterfaceWhenDoesNotImplementInterfaceThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).implementsInterface(
Callable.class)).withMessageContaining("to contain:");
}
@Test
void hasMethodNamedWhenHasName() {
MethodAssert methodAssert = assertThat(this.sourceFile).hasMethodNamed("main");
assertThat(methodAssert).isNotNull();
}
@Test
void hasMethodNameWhenDoesNotHaveMethodThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).hasMethodNamed(
"missing")).withMessageContaining("to contain method");
}
@Test
void hasMethodNameWhenHasMultipleMethodsWithNameThrowsException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).hasMethodNamed(
"run")).withMessageContaining("to contain unique method");
}
@Test
void hasMethodWhenHasMethod() {
MethodAssert methodAssert = assertThat(this.sourceFile).hasMethod("run",
String.class);
assertThat(methodAssert).isNotNull();
}
@Test
void hasMethodWhenDoesNotHaveMethod() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(this.sourceFile).hasMethod("run",
Integer.class)).withMessageContaining(
"to contain").withMessageContaining(
"run(java.lang.Integer");
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.aot.test.generator.file;
import java.io.IOException;
import com.thoughtworks.qdox.model.JavaSource;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link SourceFile}.
*
* @author Phillip Webb
*/
class SourceFileTests {
private static final String HELLO_WORLD = """
package com.example.helloworld;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
""";
@Test
void ofWhenContentIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(
() -> SourceFile.of((WritableContent) null)).withMessage(
"'writableContent' must not to be empty");
}
@Test
void ofWhenContentIsEmptyThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> SourceFile.of("")).withMessage(
"WritableContent did not append any content");
}
@Test
void ofWhenSourceDefinesNoClassThrowsException() {
assertThatIllegalStateException().isThrownBy(
() -> SourceFile.of("package com.example;")).withMessageContaining(
"Unable to parse").havingCause().withMessage(
"Source must define a single class");
}
@Test
void ofWhenSourceDefinesMultipleClassesThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> SourceFile.of(
"public class One {}\npublic class Two{}")).withMessageContaining(
"Unable to parse").havingCause().withMessage(
"Source must define a single class");
}
@Test
void ofWhenSourceCannotBeParsedThrowsException() {
assertThatIllegalStateException().isThrownBy(
() -> SourceFile.of("well this is broken {")).withMessageContaining(
"Unable to parse source file content");
}
@Test
void ofWithoutPathDeducesPath() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
assertThat(sourceFile.getPath()).isEqualTo(
"com/example/helloworld/HelloWorld.java");
}
@Test
void ofWithPathUsesPath() {
SourceFile sourceFile = SourceFile.of("com/example/DifferentPath.java",
HELLO_WORLD);
assertThat(sourceFile.getPath()).isEqualTo("com/example/DifferentPath.java");
}
@Test
void getContentReturnsContent() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
assertThat(sourceFile.getContent()).isEqualTo(HELLO_WORLD);
}
@Test
void getJavaSourceReturnsJavaSource() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
assertThat(sourceFile.getJavaSource()).isInstanceOf(JavaSource.class);
}
@Test
@SuppressWarnings("deprecation")
void assertThatReturnsAssert() {
SourceFile sourceFile = SourceFile.of(HELLO_WORLD);
assertThat(sourceFile.assertThat()).isInstanceOf(SourceFileAssert.class);
}
@Test
void createFromJavaPoetStyleApi() {
JavaFile javaFile = new JavaFile(HELLO_WORLD);
SourceFile sourceFile = SourceFile.of(javaFile::writeTo);
assertThat(sourceFile.getContent()).isEqualTo(HELLO_WORLD);
}
/**
* JavaPoet style API with a {@code writeTo} method.
*/
static class JavaFile {
private final String content;
JavaFile(String content) {
this.content = content;
}
void writeTo(Appendable out) throws IOException {
out.append(this.content);
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.aot.test.generator.file;
import java.util.Iterator;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatObject;
/**
* Tests for {@link SourceFiles}.
*
* @author Phillip Webb
*/
class SourceFilesTests {
private static final SourceFile SOURCE_FILE_1 = SourceFile.of(
"public class Test1 {}");
private static final SourceFile SOURCE_FILE_2 = SourceFile.of(
"public class Test2 {}");
@Test
void noneReturnsNone() {
SourceFiles none = SourceFiles.none();
assertThat(none).isNotNull();
assertThat(none.isEmpty()).isTrue();
}
@Test
void ofCreatesSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
assertThat(sourceFiles).containsExactly(SOURCE_FILE_1, SOURCE_FILE_2);
}
@Test
void andAddsSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1);
SourceFiles added = sourceFiles.and(SOURCE_FILE_2);
assertThat(sourceFiles).containsExactly(SOURCE_FILE_1);
assertThat(added).containsExactly(SOURCE_FILE_1, SOURCE_FILE_2);
}
@Test
void andSourceFilesAddsSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1);
SourceFiles added = sourceFiles.and(SourceFiles.of(SOURCE_FILE_2));
assertThat(sourceFiles).containsExactly(SOURCE_FILE_1);
assertThat(added).containsExactly(SOURCE_FILE_1, SOURCE_FILE_2);
}
@Test
void iteratorIteratesSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
Iterator<SourceFile> iterator = sourceFiles.iterator();
assertThat(iterator.next()).isEqualTo(SOURCE_FILE_1);
assertThat(iterator.next()).isEqualTo(SOURCE_FILE_2);
assertThat(iterator.hasNext()).isFalse();
}
@Test
void streamStreamsSourceFiles() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
assertThat(sourceFiles.stream()).containsExactly(SOURCE_FILE_1, SOURCE_FILE_2);
}
@Test
void isEmptyWhenEmptyReturnsTrue() {
SourceFiles sourceFiles = SourceFiles.of();
assertThat(sourceFiles.isEmpty()).isTrue();
}
@Test
void isEmptyWhenNotEmptyReturnsFalse() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1);
assertThat(sourceFiles.isEmpty()).isFalse();
}
@Test
void getWhenHasFileReturnsFile() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1);
assertThat(sourceFiles.get("Test1.java")).isNotNull();
}
@Test
void getWhenMissingFileReturnsNull() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_2);
assertThatObject(sourceFiles.get("Test1.java")).isNull();
}
@Test
void getSingleWhenHasNoFilesThrowsException() {
assertThatIllegalStateException().isThrownBy(
() -> SourceFiles.none().getSingle());
}
@Test
void getSingleWhenHasMultipleFilesThrowsException() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
assertThatIllegalStateException().isThrownBy(() -> sourceFiles.getSingle());
}
@Test
void getSingleWhenHasSingleFileReturnsFile() {
SourceFiles sourceFiles = SourceFiles.of(SOURCE_FILE_1);
assertThat(sourceFiles.getSingle()).isEqualTo(SOURCE_FILE_1);
}
@Test
void equalsAndHashCode() {
SourceFiles s1 = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
SourceFiles s2 = SourceFiles.of(SOURCE_FILE_1, SOURCE_FILE_2);
SourceFiles s3 = SourceFiles.of(SOURCE_FILE_1);
assertThat(s1.hashCode()).isEqualTo(s2.hashCode());
assertThatObject(s1).isEqualTo(s2).isNotEqualTo(s3);
}
}