See gh-31331
This commit is contained in:
Stephane Nicoll 2024-06-24 18:04:42 +02:00
parent 8ef74dfdad
commit 0ea7af7465
2 changed files with 111 additions and 19 deletions

View File

@ -170,11 +170,14 @@ public abstract class GeneratedFiles {
} }
/** /**
* Add a generated file of the specified {@link Kind} with the given * Handle a generated file of the specified {@link Kind} with the given
* {@linkplain FileHandler handler}. * {@linkplain FileHandler handler}. The file handler lets you consume
* @param kind the kind of file being written * the content of the already generated file, if any and provide a way
* to override its content if necessary.
* @param kind the kind of file
* @param path the relative path of the file * @param path the relative path of the file
* @param handler a consumer of a {@link FileHandler} for the file * @param handler a consumer of a {@link FileHandler} for the file
* @since 6.2
*/ */
public abstract void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler); public abstract void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler);
@ -235,6 +238,8 @@ public abstract class GeneratedFiles {
/** /**
* Provide access to a particular file and offer convenient method to save * Provide access to a particular file and offer convenient method to save
* or override its content. * or override its content.
*
* @since 6.2
*/ */
public abstract static class FileHandler { public abstract static class FileHandler {

View File

@ -19,12 +19,14 @@ package org.springframework.aot.generate;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import org.assertj.core.api.AbstractStringAssert; import org.assertj.core.api.AbstractStringAssert;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GeneratedFiles.FileHandler;
import org.springframework.aot.generate.GeneratedFiles.Kind; import org.springframework.aot.generate.GeneratedFiles.Kind;
import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamSource; import org.springframework.core.io.InputStreamSource;
@ -37,6 +39,7 @@ import org.springframework.util.function.ThrowingConsumer;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/** /**
* Tests for {@link GeneratedFiles}. * Tests for {@link GeneratedFiles}.
@ -157,18 +160,80 @@ class GeneratedFilesTests {
assertThatFileAdded(Kind.SOURCE, "com/example/HelloWorld.java").isEqualTo("{}"); assertThatFileAdded(Kind.SOURCE, "com/example/HelloWorld.java").isEqualTo("{}");
} }
private AbstractStringAssert<?> assertThatFileAdded(Kind kind, String path) @Test
void handleFileWhenFileDoesNotExist() throws IOException {
this.generatedFiles.setFileHandler(new TestFileHandler());
AtomicBoolean called = new AtomicBoolean(false);
this.generatedFiles.handleFile(Kind.RESOURCE, "META-INF/test", handler -> {
called.set(true);
handler.create(createSource("content"));
});
assertThat(called).isTrue();
assertThatFileAdded(Kind.RESOURCE, "META-INF/test").isEqualTo("content").hasOverride(false);
}
@Test
void handleFileWhenFileExistsCanOverride() throws IOException {
this.generatedFiles.setFileHandler(new TestFileHandler(createSource("existing")));
AtomicBoolean called = new AtomicBoolean(false);
this.generatedFiles.handleFile(Kind.RESOURCE, "META-INF/test", handler -> {
called.set(true);
handler.override(createSource("overridden"));
});
assertThat(called).isTrue();
assertThatFileAdded(Kind.RESOURCE, "META-INF/test").isEqualTo("overridden").hasOverride(true);
}
@Test
void handleFileWhenFileExistsCanOverrideUsingExistingContent() throws IOException {
this.generatedFiles.setFileHandler(new TestFileHandler(createSource("existing")));
AtomicBoolean called = new AtomicBoolean(false);
this.generatedFiles.handleFile(Kind.RESOURCE, "META-INF/test", handler -> {
called.set(true);
String existing = readSource(handler.getContent());
handler.override(createSource(existing+"-override"));
});
assertThat(called).isTrue();
assertThatFileAdded(Kind.RESOURCE, "META-INF/test").isEqualTo("existing-override").hasOverride(true);
}
@Test
void handleFileWhenFileExistsFailedToCreate() {
TestFileHandler fileHandler = new TestFileHandler(createSource("existing"));
this.generatedFiles.setFileHandler(fileHandler);
assertThatIllegalStateException()
.isThrownBy(() -> this.generatedFiles.handleFile(Kind.RESOURCE, "META-INF/test", handler ->
handler.create(createSource("should fail"))))
.withMessage("%s already exists".formatted(fileHandler));
}
private static InputStreamSource createSource(String content) {
return new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8));
}
private static String readSource(InputStreamSource content) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
content.getInputStream().transferTo(out);
return out.toString(StandardCharsets.UTF_8);
}
private GeneratedFileAssert assertThatFileAdded(Kind kind, String path)
throws IOException { throws IOException {
return this.generatedFiles.assertThatFileAdded(kind, path); return this.generatedFiles.assertThatFileAdded(kind, path);
} }
static class TestGeneratedFiles extends GeneratedFiles { static class TestGeneratedFiles extends GeneratedFiles {
private Kind kind; private Kind kind;
private String path; private String path;
private final TestFileHandler fileHandler = new TestFileHandler(); private TestFileHandler fileHandler = new TestFileHandler();
void setFileHandler(TestFileHandler fileHandler) {
this.fileHandler = fileHandler;
}
@Override @Override
public void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler) { public void handleFile(Kind kind, String path, ThrowingConsumer<FileHandler> handler) {
@ -177,14 +242,28 @@ class GeneratedFilesTests {
handler.accept(this.fileHandler); handler.accept(this.fileHandler);
} }
AbstractStringAssert<?> assertThatFileAdded(Kind kind, String path) GeneratedFileAssert assertThatFileAdded(Kind kind, String path)
throws IOException { throws IOException {
assertThat(this.kind).as("kind").isEqualTo(kind); assertThat(this.kind).as("kind").isEqualTo(kind);
assertThat(this.path).as("path").isEqualTo(path); assertThat(this.path).as("path").isEqualTo(path);
assertThat(this.fileHandler.content).as("content").isNotNull(); assertThat(this.fileHandler.content).as("content").isNotNull();
ByteArrayOutputStream out = new ByteArrayOutputStream(); return new GeneratedFileAssert(this.fileHandler);
this.fileHandler.content.getInputStream().transferTo(out); }
return assertThat(out.toString(StandardCharsets.UTF_8)); }
private static class GeneratedFileAssert extends AbstractStringAssert<GeneratedFileAssert> {
private final TestFileHandler fileHandler;
GeneratedFileAssert(TestFileHandler fileHandler) throws IOException {
super(readSource(fileHandler.content), GeneratedFileAssert.class);
this.fileHandler = fileHandler;
}
public GeneratedFileAssert hasOverride(boolean expected) {
assertThat(this.fileHandler.override).isEqualTo(expected);
return this.myself;
}
} }
private static class TestFileHandler extends FileHandler { private static class TestFileHandler extends FileHandler {
@ -192,14 +271,22 @@ class GeneratedFilesTests {
@Nullable @Nullable
private InputStreamSource content; private InputStreamSource content;
@Nullable
private Boolean override;
TestFileHandler(@Nullable InputStreamSource content) {
super(content != null, () -> content);
this.content = content;
}
TestFileHandler() { TestFileHandler() {
super(false, () -> null); this(null);
} }
@Override @Override
protected void copy(InputStreamSource content, boolean override) { protected void copy(InputStreamSource content, boolean override) {
this.content = content; this.content = content;
} this.override = override;
} }
} }