Browse Source
This commit adds a 'org.springframework.boot.configuration-metadata' plugin to be used for projects that only define manual metadata. Such project do not need the annotation processor, but do not to check that the structure of the metadata content matches the same rules. Closes gh-47984pull/47980/head
7 changed files with 611 additions and 187 deletions
@ -0,0 +1,77 @@
@@ -0,0 +1,77 @@
|
||||
/* |
||||
* Copyright 2012-present 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.boot.build.context.properties; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
import org.gradle.api.DefaultTask; |
||||
import org.gradle.api.file.RegularFileProperty; |
||||
import org.gradle.api.provider.ListProperty; |
||||
import org.gradle.api.provider.Property; |
||||
import org.gradle.api.tasks.Input; |
||||
import org.gradle.api.tasks.InputFile; |
||||
import org.gradle.api.tasks.OutputFile; |
||||
import org.gradle.api.tasks.PathSensitive; |
||||
import org.gradle.api.tasks.PathSensitivity; |
||||
import org.gradle.api.tasks.SourceTask; |
||||
import org.gradle.api.tasks.TaskAction; |
||||
import org.gradle.api.tasks.VerificationException; |
||||
|
||||
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report; |
||||
|
||||
/** |
||||
* {@link SourceTask} that checks manual Spring configuration metadata files. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
public abstract class CheckManualSpringConfigurationMetadata extends DefaultTask { |
||||
|
||||
private final File projectDir; |
||||
|
||||
public CheckManualSpringConfigurationMetadata() { |
||||
this.projectDir = getProject().getProjectDir(); |
||||
} |
||||
|
||||
@OutputFile |
||||
public abstract RegularFileProperty getReportLocation(); |
||||
|
||||
@InputFile |
||||
@PathSensitive(PathSensitivity.RELATIVE) |
||||
public abstract Property<File> getMetadataLocation(); |
||||
|
||||
@Input |
||||
public abstract ListProperty<String> getExclusions(); |
||||
|
||||
@TaskAction |
||||
void check() throws IOException { |
||||
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer( |
||||
List.of(getMetadataLocation().get())); |
||||
Report report = new Report(this.projectDir); |
||||
analyzer.analyzeSort(report); |
||||
analyzer.analyzePropertyDescription(report, getExclusions().get()); |
||||
File reportFile = getReportLocation().get().getAsFile(); |
||||
report.write(reportFile); |
||||
if (report.hasProblems()) { |
||||
throw new VerificationException( |
||||
"Problems found in manual Spring configuration metadata. See " + reportFile + " for details."); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
/* |
||||
* Copyright 2012-present 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.boot.build.context.properties; |
||||
|
||||
import java.io.File; |
||||
|
||||
import org.gradle.api.Plugin; |
||||
import org.gradle.api.Project; |
||||
import org.gradle.api.plugins.JavaPlugin; |
||||
import org.gradle.api.plugins.JavaPluginExtension; |
||||
import org.gradle.api.provider.Provider; |
||||
import org.gradle.api.tasks.SourceSet; |
||||
import org.gradle.api.tasks.TaskProvider; |
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin; |
||||
import org.gradle.language.jvm.tasks.ProcessResources; |
||||
|
||||
/** |
||||
* {@link Plugin} for projects that <em>only</em> define manual configuration metadata. |
||||
* When applied, the plugin registers a {@link CheckManualSpringConfigurationMetadata} |
||||
* task and configures the {@code check} task to depend upon it. |
||||
* |
||||
* @author Andy Wilkinson |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
public class ConfigurationMetadataPlugin implements Plugin<Project> { |
||||
|
||||
/** |
||||
* Name of the {@link CheckAdditionalSpringConfigurationMetadata} task. |
||||
*/ |
||||
public static final String CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = "checkManualSpringConfigurationMetadata"; |
||||
|
||||
@Override |
||||
public void apply(Project project) { |
||||
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerCheckAdditionalMetadataTask(project)); |
||||
} |
||||
|
||||
private void registerCheckAdditionalMetadataTask(Project project) { |
||||
TaskProvider<CheckManualSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks() |
||||
.register(CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME, |
||||
CheckManualSpringConfigurationMetadata.class); |
||||
checkConfigurationMetadata.configure((check) -> { |
||||
SourceSet mainSourceSet = project.getExtensions() |
||||
.getByType(JavaPluginExtension.class) |
||||
.getSourceSets() |
||||
.getByName(SourceSet.MAIN_SOURCE_SET_NAME); |
||||
|
||||
Provider<File> manualMetadataLocation = project.getTasks() |
||||
.named(mainSourceSet.getProcessResourcesTaskName(), ProcessResources.class) |
||||
.map((processResources) -> new File(processResources.getDestinationDir(), |
||||
"META-INF/spring-configuration-metadata.json")); |
||||
check.getMetadataLocation().set(manualMetadataLocation); |
||||
check.getReportLocation() |
||||
.set(project.getLayout() |
||||
.getBuildDirectory() |
||||
.file("reports/manual-spring-configuration-metadata/check.txt")); |
||||
}); |
||||
project.getTasks() |
||||
.named(LifecycleBasePlugin.CHECK_TASK_NAME) |
||||
.configure((check) -> check.dependsOn(checkConfigurationMetadata)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,251 @@
@@ -0,0 +1,251 @@
|
||||
/* |
||||
* Copyright 2012-present 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.boot.build.context.properties; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.io.PrintWriter; |
||||
import java.io.StringWriter; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.StandardOpenOption; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.function.Consumer; |
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.util.MultiValueMap; |
||||
import org.springframework.util.function.SingletonSupplier; |
||||
|
||||
/** |
||||
* Check configuration metadata for inconsistencies. The available checks are: |
||||
* <ul> |
||||
* <li>Metadata element should be sorted alphabetically: {@link #analyzeSort(Report)}</li> |
||||
* <li>Property must have a description: |
||||
* {@link #analyzePropertyDescription(Report, List)}</li> |
||||
* </ul> |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class ConfigurationPropertiesAnalyzer { |
||||
|
||||
private final Collection<File> sources; |
||||
|
||||
private final SingletonSupplier<ObjectMapper> objectMapperSupplier; |
||||
|
||||
ConfigurationPropertiesAnalyzer(Collection<File> sources) { |
||||
if (sources.isEmpty()) { |
||||
throw new IllegalArgumentException("At least one source should be provided"); |
||||
} |
||||
this.sources = sources; |
||||
this.objectMapperSupplier = SingletonSupplier.of(ObjectMapper::new); |
||||
} |
||||
|
||||
void analyzeSort(Report report) throws IOException { |
||||
for (File source : this.sources) { |
||||
report.registerAnalysis(source, analyzeSort(source)); |
||||
} |
||||
} |
||||
|
||||
private Analysis analyzeSort(File source) throws IOException { |
||||
Map<String, Object> json = readJsonContent(source); |
||||
Analysis analysis = new Analysis("Metadata element order:"); |
||||
analyzeMetadataElementsSort("groups", json, analysis); |
||||
analyzeMetadataElementsSort("properties", json, analysis); |
||||
analyzeMetadataElementsSort("hints", json, analysis); |
||||
return analysis; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private void analyzeMetadataElementsSort(String key, Map<String, Object> json, Analysis analysis) { |
||||
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.getOrDefault(key, Collections.emptyList()); |
||||
List<String> names = groups.stream().map((group) -> (String) group.get("name")).toList(); |
||||
List<String> sortedNames = names.stream().sorted().toList(); |
||||
for (int i = 0; i < names.size(); i++) { |
||||
String actual = names.get(i); |
||||
String expected = sortedNames.get(i); |
||||
if (!actual.equals(expected)) { |
||||
analysis.addItem("Wrong order at $." + key + "[" + i + "].name - expected '" + expected |
||||
+ "' but found '" + actual + "'"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void analyzePropertyDescription(Report report, List<String> exclusions) throws IOException { |
||||
for (File source : this.sources) { |
||||
report.registerAnalysis(source, analyzePropertyDescription(source, exclusions)); |
||||
} |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private Analysis analyzePropertyDescription(File source, List<String> exclusions) throws IOException { |
||||
Map<String, Object> json = readJsonContent(source); |
||||
Analysis analysis = new Analysis("The following properties have no description:"); |
||||
List<Map<String, Object>> properties = (List<Map<String, Object>>) json.get("properties"); |
||||
for (Map<String, Object> property : properties) { |
||||
String name = (String) property.get("name"); |
||||
if (!isDeprecated(property) && !isDescribed(property) && !isExcluded(exclusions, name)) { |
||||
analysis.addItem(name); |
||||
} |
||||
} |
||||
return analysis; |
||||
} |
||||
|
||||
private boolean isExcluded(List<String> exclusions, String propertyName) { |
||||
for (String exclusion : exclusions) { |
||||
if (propertyName.equals(exclusion)) { |
||||
return true; |
||||
} |
||||
if (exclusion.endsWith(".*")) { |
||||
if (propertyName.startsWith(exclusion.substring(0, exclusion.length() - 2))) { |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private boolean isDeprecated(Map<String, Object> property) { |
||||
return property.get("deprecation") != null; |
||||
} |
||||
|
||||
private boolean isDescribed(Map<String, Object> property) { |
||||
return property.get("description") != null; |
||||
} |
||||
|
||||
private Map<String, Object> readJsonContent(File source) throws IOException { |
||||
return this.objectMapperSupplier.obtain().readValue(source, new TypeReference<Map<String, Object>>() { |
||||
}); |
||||
} |
||||
|
||||
private static <T> void writeAll(PrintWriter writer, Iterable<T> elements, Consumer<T> itemWriter) { |
||||
Iterator<T> it = elements.iterator(); |
||||
while (it.hasNext()) { |
||||
itemWriter.accept(it.next()); |
||||
if (it.hasNext()) { |
||||
writer.println(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static class Report { |
||||
|
||||
private final File baseDirectory; |
||||
|
||||
private final MultiValueMap<File, Analysis> analyses = new LinkedMultiValueMap<>(); |
||||
|
||||
Report(File baseDirectory) { |
||||
this.baseDirectory = baseDirectory; |
||||
} |
||||
|
||||
void registerAnalysis(File path, Analysis analysis) { |
||||
this.analyses.add(path, analysis); |
||||
} |
||||
|
||||
boolean hasProblems() { |
||||
return this.analyses.values() |
||||
.stream() |
||||
.anyMatch((candidates) -> candidates.stream().anyMatch(Analysis::hasProblems)); |
||||
} |
||||
|
||||
List<Analysis> getAnalyses(File source) { |
||||
return this.analyses.getOrDefault(source, Collections.emptyList()); |
||||
} |
||||
|
||||
/** |
||||
* Write this report to the given {@code file}. |
||||
* @param file the file to write the report to |
||||
*/ |
||||
void write(File file) throws IOException { |
||||
Files.writeString(file.toPath(), createContent(), StandardOpenOption.CREATE, |
||||
StandardOpenOption.TRUNCATE_EXISTING); |
||||
} |
||||
|
||||
private String createContent() { |
||||
if (this.analyses.isEmpty()) { |
||||
return "No problems found."; |
||||
} |
||||
StringWriter out = new StringWriter(); |
||||
try (PrintWriter writer = new PrintWriter(out)) { |
||||
writeAll(writer, this.analyses.entrySet(), (entry) -> { |
||||
writer.println(this.baseDirectory.toPath().relativize(entry.getKey().toPath())); |
||||
boolean hasProblems = entry.getValue().stream().anyMatch(Analysis::hasProblems); |
||||
if (hasProblems) { |
||||
writeAll(writer, entry.getValue(), (analysis) -> analysis.createDetails(writer)); |
||||
} |
||||
else { |
||||
writer.println("No problems found."); |
||||
} |
||||
}); |
||||
} |
||||
return out.toString(); |
||||
} |
||||
|
||||
} |
||||
|
||||
static class Analysis { |
||||
|
||||
private final String header; |
||||
|
||||
private final List<String> items; |
||||
|
||||
Analysis(String header) { |
||||
this.header = header; |
||||
this.items = new ArrayList<>(); |
||||
} |
||||
|
||||
void addItem(String item) { |
||||
this.items.add(item); |
||||
} |
||||
|
||||
boolean hasProblems() { |
||||
return !this.items.isEmpty(); |
||||
} |
||||
|
||||
List<String> getItems() { |
||||
return this.items; |
||||
} |
||||
|
||||
void createDetails(PrintWriter writer) { |
||||
writer.println(this.header); |
||||
if (this.items.isEmpty()) { |
||||
writer.println("No problems found."); |
||||
} |
||||
else { |
||||
for (String item : this.items) { |
||||
writer.println("\t- " + item); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
StringWriter out = new StringWriter(); |
||||
PrintWriter writer = new PrintWriter(out); |
||||
createDetails(writer); |
||||
return out.toString(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,185 @@
@@ -0,0 +1,185 @@
|
||||
/* |
||||
* Copyright 2012-present 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.boot.build.context.properties; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
import org.junit.jupiter.api.io.TempDir; |
||||
|
||||
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Analysis; |
||||
import org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; |
||||
|
||||
/** |
||||
* Tests for {@link ConfigurationPropertiesAnalyzer}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
*/ |
||||
class ConfigurationPropertiesAnalyzerTests { |
||||
|
||||
@Test |
||||
void createAnalyzerWithNoSource() { |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> new ConfigurationPropertiesAnalyzer(Collections.emptyList())) |
||||
.withMessage("At least one source should be provided"); |
||||
} |
||||
|
||||
@Test |
||||
void analyzeSortWithAlphabeticalOrder(@TempDir File tempDir) throws IOException { |
||||
File metadata = new File(tempDir, "metadata.json"); |
||||
Files.writeString(metadata.toPath(), """ |
||||
{ "properties": [ |
||||
{ "name": "abc"}, {"name": "def"}, {"name": "xyz"} |
||||
] |
||||
}"""); |
||||
Report report = new Report(tempDir); |
||||
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata)); |
||||
analyzer.analyzeSort(report); |
||||
assertThat(report.hasProblems()).isFalse(); |
||||
assertThat(report.getAnalyses(metadata)).singleElement() |
||||
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty())); |
||||
} |
||||
|
||||
@Test |
||||
void analyzeSortWithViolations(@TempDir File tempDir) throws IOException { |
||||
File metadata = new File(tempDir, "metadata.json"); |
||||
Files.writeString(metadata.toPath(), """ |
||||
{ "properties": [ |
||||
{ "name": "def"}, {"name": "abc"}, {"name": "xyz"} |
||||
] |
||||
}"""); |
||||
Report report = new Report(tempDir); |
||||
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata)); |
||||
analyzer.analyzeSort(report); |
||||
assertThat(report.hasProblems()).isTrue(); |
||||
assertThat(report.getAnalyses(metadata)).singleElement() |
||||
.satisfies((analysis) -> assertThat(analysis.getItems()).containsExactly( |
||||
"Wrong order at $.properties[0].name - expected 'abc' but found 'def'", |
||||
"Wrong order at $.properties[1].name - expected 'def' but found 'abc'")); |
||||
} |
||||
|
||||
@Test |
||||
void analyzePropertyDescription(@TempDir File tempDir) throws IOException { |
||||
File metadata = new File(tempDir, "metadata.json"); |
||||
Files.writeString(metadata.toPath(), """ |
||||
{ "properties": [ |
||||
{ "name": "abc", "description": "This is abc." }, |
||||
{ "name": "def", "description": "This is def." }, |
||||
{ "name": "xyz", "description": "This is xyz." } |
||||
] |
||||
}"""); |
||||
Report report = new Report(tempDir); |
||||
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata)); |
||||
analyzer.analyzePropertyDescription(report, List.of()); |
||||
assertThat(report.hasProblems()).isFalse(); |
||||
assertThat(report.getAnalyses(metadata)).singleElement() |
||||
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty())); |
||||
} |
||||
|
||||
@Test |
||||
void analyzePropertyDescriptionWithMissingDescription(@TempDir File tempDir) throws IOException { |
||||
File metadata = new File(tempDir, "metadata.json"); |
||||
Files.writeString(metadata.toPath(), """ |
||||
{ "properties": [ |
||||
{ "name": "abc", "description": "This is abc." }, |
||||
{ "name": "def" }, |
||||
{ "name": "xyz", "description": "This is xyz." } |
||||
] |
||||
}"""); |
||||
Report report = new Report(tempDir); |
||||
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata)); |
||||
analyzer.analyzePropertyDescription(report, List.of()); |
||||
assertThat(report.hasProblems()).isTrue(); |
||||
assertThat(report.getAnalyses(metadata)).singleElement() |
||||
.satisfies(((analysis) -> assertThat(analysis.getItems()).containsExactly("def"))); |
||||
} |
||||
|
||||
@Test |
||||
void writeEmptyReport(@TempDir File tempDir) throws IOException { |
||||
assertThat(writeToFile(tempDir, new Report(tempDir))).hasContent("No problems found."); |
||||
} |
||||
|
||||
@Test |
||||
void writeReportWithNoProblemsFound(@TempDir File tempDir) throws IOException { |
||||
Report report = new Report(tempDir); |
||||
File first = new File(tempDir, "metadata-1.json"); |
||||
report.registerAnalysis(first, new Analysis("Check for things:")); |
||||
File second = new File(tempDir, "metadata-2.json"); |
||||
report.registerAnalysis(second, new Analysis("Check for other things:")); |
||||
assertThat(writeToFile(tempDir, report)).content().isEqualTo(""" |
||||
metadata-1.json |
||||
No problems found. |
||||
|
||||
metadata-2.json |
||||
No problems found. |
||||
"""); |
||||
} |
||||
|
||||
@Test |
||||
void writeReportWithOneProblem(@TempDir File tempDir) throws IOException { |
||||
Report report = new Report(tempDir); |
||||
File metadata = new File(tempDir, "metadata-1.json"); |
||||
Analysis analysis = new Analysis("Check for things:"); |
||||
analysis.addItem("Should not be deprecated"); |
||||
report.registerAnalysis(metadata, analysis); |
||||
report.registerAnalysis(metadata, new Analysis("Check for other things:")); |
||||
assertThat(writeToFile(tempDir, report)).content().isEqualTo(""" |
||||
metadata-1.json |
||||
Check for things: |
||||
- Should not be deprecated |
||||
|
||||
Check for other things: |
||||
No problems found. |
||||
"""); |
||||
} |
||||
|
||||
@Test |
||||
void writeReportWithSeveralProblems(@TempDir File tempDir) throws IOException { |
||||
Report report = new Report(tempDir); |
||||
File metadata = new File(tempDir, "metadata-1.json"); |
||||
Analysis firstAnalysis = new Analysis("Check for things:"); |
||||
firstAnalysis.addItem("Should not be deprecated"); |
||||
firstAnalysis.addItem("Should not be public"); |
||||
report.registerAnalysis(metadata, firstAnalysis); |
||||
Analysis secondAnalysis = new Analysis("Check for other things:"); |
||||
secondAnalysis.addItem("Field 'this' not expected"); |
||||
report.registerAnalysis(metadata, secondAnalysis); |
||||
assertThat(writeToFile(tempDir, report)).content().isEqualTo(""" |
||||
metadata-1.json |
||||
Check for things: |
||||
- Should not be deprecated |
||||
- Should not be public |
||||
|
||||
Check for other things: |
||||
- Field 'this' not expected |
||||
"""); |
||||
} |
||||
|
||||
private File writeToFile(File directory, Report report) throws IOException { |
||||
File file = new File(directory, "report.txt"); |
||||
report.write(file); |
||||
return file; |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue