Skip to content

Commit 11622e0

Browse files
authored
Breaking changes to Spotless' internal testing infrastructure testlib (#1443)
2 parents 86404f1 + f0b74d8 commit 11622e0

18 files changed

+380
-361
lines changed

CHANGES.md

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1313
### Changes
1414
* Bump the dev version of Gradle from `7.5.1` to `7.6` ([#1409](https://github.com/diffplug/spotless/pull/1409))
1515
* We also removed the no-longer-required dependency `org.codehaus.groovy:groovy-xml`
16+
* Breaking changes to Spotless' internal testing infrastructure `testlib` ([#1443](https://github.com/diffplug/spotless/pull/1443))
17+
* `ResourceHarness` no longer has any duplicated functionality which was also present in `StepHarness`
18+
* `StepHarness` now operates on `Formatter` rather than a `FormatterStep`
19+
* `StepHarnessWithFile` now takes a `ResourceHarness` in its constructor to handle the file manipulation parts
20+
* Standardized that we test exception *messages*, not types, which will ease the transition to linting later on
1621

1722
## [2.31.1] - 2023-01-02
1823
### Fixed

lib-extra/src/test/java/com/diffplug/spotless/extra/GitAttributesTest.java

+10-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2022 DiffPlug
2+
* Copyright 2016-2023 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,24 +26,19 @@
2626
import org.eclipse.jgit.api.errors.GitAPIException;
2727
import org.junit.jupiter.api.Test;
2828

29-
import com.diffplug.common.base.Errors;
3029
import com.diffplug.common.base.StringPrinter;
3130
import com.diffplug.spotless.LineEnding;
3231
import com.diffplug.spotless.ResourceHarness;
3332

3433
class GitAttributesTest extends ResourceHarness {
3534
private List<File> testFiles(String prefix) {
36-
try {
37-
List<File> result = new ArrayList<>();
38-
for (String path : TEST_PATHS) {
39-
String prefixedPath = prefix + path;
40-
setFile(prefixedPath).toContent("");
41-
result.add(newFile(prefixedPath));
42-
}
43-
return result;
44-
} catch (IOException e) {
45-
throw Errors.asRuntime(e);
35+
List<File> result = new ArrayList<>();
36+
for (String path : TEST_PATHS) {
37+
String prefixedPath = prefix + path;
38+
setFile(prefixedPath).toContent("");
39+
result.add(newFile(prefixedPath));
4640
}
41+
return result;
4742
}
4843

4944
private List<File> testFiles() {
@@ -53,7 +48,7 @@ private List<File> testFiles() {
5348
private static final List<String> TEST_PATHS = Arrays.asList("someFile", "subfolder/someFile", "MANIFEST.MF", "subfolder/MANIFEST.MF");
5449

5550
@Test
56-
void cacheTest() throws IOException {
51+
void cacheTest() {
5752
setFile(".gitattributes").toContent(StringPrinter.buildStringFromLines(
5853
"* eol=lf",
5954
"*.MF eol=crlf"));
@@ -84,7 +79,7 @@ void cacheTest() throws IOException {
8479
}
8580

8681
@Test
87-
void policyTest() throws IOException {
82+
void policyTest() {
8883
setFile(".gitattributes").toContent(StringPrinter.buildStringFromLines(
8984
"* eol=lf",
9085
"*.MF eol=crlf"));
@@ -96,7 +91,7 @@ void policyTest() throws IOException {
9691
}
9792

9893
@Test
99-
void policyDefaultLineEndingTest() throws GitAPIException, IOException {
94+
void policyDefaultLineEndingTest() throws GitAPIException {
10095
Git git = Git.init().setDirectory(rootFolder()).call();
10196
git.close();
10297
setFile(".git/config").toContent(StringPrinter.buildStringFromLines(

testlib/src/main/java/com/diffplug/spotless/ResourceHarness.java

+21-34
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2023 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ protected File rootFolder() {
5454
}
5555

5656
/** Returns a new child of the root folder. */
57-
protected File newFile(String subpath) throws IOException {
57+
protected File newFile(String subpath) {
5858
return new File(rootFolder(), subpath);
5959
}
6060

@@ -85,16 +85,16 @@ protected void replace(String path, String toReplace, String replaceWith) throws
8585
}
8686

8787
/** Returns the contents of the given file from the src/test/resources directory. */
88-
protected static String getTestResource(String filename) throws IOException {
88+
protected static String getTestResource(String filename) {
8989
URL url = ResourceHarness.class.getResource("/" + filename);
9090
if (url == null) {
9191
throw new IllegalArgumentException("No such resource " + filename);
9292
}
93-
return Resources.toString(url, StandardCharsets.UTF_8);
93+
return ThrowingEx.get(() -> LineEnding.toUnix(Resources.toString(url, StandardCharsets.UTF_8)));
9494
}
9595

9696
/** Returns Files (in a temporary folder) which has the contents of the given file from the src/test/resources directory. */
97-
protected List<File> createTestFiles(String... filenames) throws IOException {
97+
protected List<File> createTestFiles(String... filenames) {
9898
List<File> files = new ArrayList<>(filenames.length);
9999
for (String filename : filenames) {
100100
files.add(createTestFile(filename));
@@ -103,47 +103,30 @@ protected List<File> createTestFiles(String... filenames) throws IOException {
103103
}
104104

105105
/** Returns a File (in a temporary folder) which has the contents of the given file from the src/test/resources directory. */
106-
protected File createTestFile(String filename) throws IOException {
106+
protected File createTestFile(String filename) {
107107
return createTestFile(filename, UnaryOperator.identity());
108108
}
109109

110110
/**
111111
* Returns a File (in a temporary folder) which has the contents, possibly processed, of the given file from the
112112
* src/test/resources directory.
113113
*/
114-
protected File createTestFile(String filename, UnaryOperator<String> fileContentsProcessor) throws IOException {
114+
protected File createTestFile(String filename, UnaryOperator<String> fileContentsProcessor) {
115115
int lastSlash = filename.lastIndexOf('/');
116116
String name = lastSlash >= 0 ? filename.substring(lastSlash) : filename;
117117
File file = newFile(name);
118118
file.getParentFile().mkdirs();
119-
Files.write(file.toPath(), fileContentsProcessor.apply(getTestResource(filename)).getBytes(StandardCharsets.UTF_8));
119+
ThrowingEx.run(() -> Files.write(file.toPath(), fileContentsProcessor.apply(getTestResource(filename)).getBytes(StandardCharsets.UTF_8)));
120120
return file;
121121
}
122122

123-
/** Reads the given resource from "before", applies the step, and makes sure the result is "after". */
124-
protected void assertOnResources(FormatterStep step, String unformattedPath, String expectedPath) throws Throwable {
125-
assertOnResources(rawUnix -> step.format(rawUnix, new File("")), unformattedPath, expectedPath);
126-
}
127-
128-
/** Reads the given resource from "before", applies the step, and makes sure the result is "after". */
129-
protected void assertOnResources(FormatterFunc step, String unformattedPath, String expectedPath) throws Throwable {
130-
String unformatted = LineEnding.toUnix(getTestResource(unformattedPath)); // unix-ified input
131-
String formatted = step.apply(unformatted);
132-
// no windows newlines
133-
assertThat(formatted).doesNotContain("\r");
134-
135-
// unix-ify the test resource output in case git screwed it up
136-
String expected = LineEnding.toUnix(getTestResource(expectedPath)); // unix-ified output
137-
assertThat(formatted).isEqualTo(expected);
138-
}
139-
140123
@CheckReturnValue
141-
protected ReadAsserter assertFile(String path) throws IOException {
124+
protected ReadAsserter assertFile(String path) {
142125
return new ReadAsserter(newFile(path));
143126
}
144127

145128
@CheckReturnValue
146-
protected ReadAsserter assertFile(File file) throws IOException {
129+
protected ReadAsserter assertFile(File file) {
147130
return new ReadAsserter(file);
148131
}
149132

@@ -176,7 +159,7 @@ public void matches(Consumer<AbstractCharSequenceAssert<?, String>> conditions)
176159
}
177160
}
178161

179-
protected WriteAsserter setFile(String path) throws IOException {
162+
protected WriteAsserter setFile(String path) {
180163
return new WriteAsserter(newFile(path));
181164
}
182165

@@ -188,21 +171,25 @@ private WriteAsserter(File file) {
188171
this.file = file;
189172
}
190173

191-
public File toLines(String... lines) throws IOException {
174+
public File toLines(String... lines) {
192175
return toContent(String.join("\n", Arrays.asList(lines)));
193176
}
194177

195-
public File toContent(String content) throws IOException {
178+
public File toContent(String content) {
196179
return toContent(content, StandardCharsets.UTF_8);
197180
}
198181

199-
public File toContent(String content, Charset charset) throws IOException {
200-
Files.write(file.toPath(), content.getBytes(charset));
182+
public File toContent(String content, Charset charset) {
183+
ThrowingEx.run(() -> {
184+
Files.write(file.toPath(), content.getBytes(charset));
185+
});
201186
return file;
202187
}
203188

204-
public File toResource(String path) throws IOException {
205-
Files.write(file.toPath(), getTestResource(path).getBytes(StandardCharsets.UTF_8));
189+
public File toResource(String path) {
190+
ThrowingEx.run(() -> {
191+
Files.write(file.toPath(), getTestResource(path).getBytes(StandardCharsets.UTF_8));
192+
});
206193
return file;
207194
}
208195

Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 DiffPlug
2+
* Copyright 2016-2023 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,31 +22,21 @@
2222
import java.nio.file.Paths;
2323
import java.util.Arrays;
2424
import java.util.Objects;
25-
import java.util.function.Consumer;
2625

27-
import org.assertj.core.api.AbstractThrowableAssert;
26+
import org.assertj.core.api.AbstractStringAssert;
2827
import org.assertj.core.api.Assertions;
2928

3029
/** An api for testing a {@code FormatterStep} that doesn't depend on the File path. DO NOT ADD FILE SUPPORT TO THIS, use {@link StepHarnessWithFile} if you need that. */
3130
public class StepHarness implements AutoCloseable {
32-
private final FormatterFunc formatter;
31+
private final Formatter formatter;
3332

34-
private StepHarness(FormatterFunc formatter) {
33+
private StepHarness(Formatter formatter) {
3534
this.formatter = Objects.requireNonNull(formatter);
3635
}
3736

3837
/** Creates a harness for testing steps which don't depend on the file. */
3938
public static StepHarness forStep(FormatterStep step) {
40-
// We don't care if an individual FormatterStep is misbehaving on line-endings, because
41-
// Formatter fixes that. No reason to care in tests either. It's likely to pop up when
42-
// running tests on Windows from time-to-time
43-
return new StepHarness(FormatterFunc.Closeable.ofDangerous(
44-
() -> {
45-
if (step instanceof FormatterStepImpl.Standard) {
46-
((FormatterStepImpl.Standard<?>) step).cleanupFormatterFunc();
47-
}
48-
},
49-
input -> LineEnding.toUnix(step.format(input, new File("")))));
39+
return forSteps(step);
5040
}
5141

5242
/** Creates a harness for testing steps which don't depend on the file. */
@@ -56,60 +46,68 @@ public static StepHarness forSteps(FormatterStep... steps) {
5646
.lineEndingsPolicy(LineEnding.UNIX.createPolicy())
5747
.encoding(StandardCharsets.UTF_8)
5848
.rootDir(Paths.get(""))
49+
.exceptionPolicy(new FormatExceptionPolicyStrict())
5950
.build());
6051
}
6152

6253
/** Creates a harness for testing a formatter whose steps don't depend on the file. */
6354
public static StepHarness forFormatter(Formatter formatter) {
64-
return new StepHarness(FormatterFunc.Closeable.ofDangerous(
65-
formatter::close,
66-
input -> formatter.compute(input, new File(""))));
55+
return new StepHarness(formatter);
6756
}
6857

6958
/** Asserts that the given element is transformed as expected, and that the result is idempotent. */
70-
public StepHarness test(String before, String after) throws Exception {
71-
String actual = formatter.apply(before);
59+
public StepHarness test(String before, String after) {
60+
String actual = formatter.compute(LineEnding.toUnix(before), new File(""));
7261
assertEquals(after, actual, "Step application failed");
7362
return testUnaffected(after);
7463
}
7564

7665
/** Asserts that the given element is idempotent w.r.t the step under test. */
77-
public StepHarness testUnaffected(String idempotentElement) throws Exception {
78-
String actual = formatter.apply(idempotentElement);
66+
public StepHarness testUnaffected(String idempotentElement) {
67+
String actual = formatter.compute(LineEnding.toUnix(idempotentElement), new File(""));
7968
assertEquals(idempotentElement, actual, "Step is not idempotent");
8069
return this;
8170
}
8271

8372
/** Asserts that the given elements in the resources directory are transformed as expected. */
84-
public StepHarness testResource(String resourceBefore, String resourceAfter) throws Exception {
73+
public StepHarness testResource(String resourceBefore, String resourceAfter) {
8574
String before = ResourceHarness.getTestResource(resourceBefore);
8675
String after = ResourceHarness.getTestResource(resourceAfter);
8776
return test(before, after);
8877
}
8978

9079
/** Asserts that the given elements in the resources directory are transformed as expected. */
91-
public StepHarness testResourceUnaffected(String resourceIdempotent) throws Exception {
80+
public StepHarness testResourceUnaffected(String resourceIdempotent) {
9281
String idempotentElement = ResourceHarness.getTestResource(resourceIdempotent);
9382
return testUnaffected(idempotentElement);
9483
}
9584

96-
/** Asserts that the given elements in the resources directory are transformed as expected. */
97-
public StepHarness testResourceException(String resourceBefore, Consumer<AbstractThrowableAssert<?, ? extends Throwable>> exceptionAssertion) throws Exception {
98-
return testException(ResourceHarness.getTestResource(resourceBefore), exceptionAssertion);
85+
public AbstractStringAssert<?> testResourceExceptionMsg(String resourceBefore) {
86+
return testExceptionMsg(ResourceHarness.getTestResource(resourceBefore));
9987
}
10088

101-
/** Asserts that the given elements in the resources directory are transformed as expected. */
102-
public StepHarness testException(String before, Consumer<AbstractThrowableAssert<?, ? extends Throwable>> exceptionAssertion) throws Exception {
103-
Throwable t = assertThrows(Throwable.class, () -> formatter.apply(before));
104-
AbstractThrowableAssert<?, ? extends Throwable> abstractAssert = Assertions.assertThat(t);
105-
exceptionAssertion.accept(abstractAssert);
106-
return this;
89+
public AbstractStringAssert<?> testExceptionMsg(String before) {
90+
try {
91+
formatter.compute(LineEnding.toUnix(before), FormatterStepImpl.SENTINEL);
92+
throw new SecurityException("Expected exception");
93+
} catch (Throwable e) {
94+
if (e instanceof SecurityException) {
95+
throw new AssertionError(e.getMessage());
96+
} else {
97+
Throwable rootCause = e;
98+
while (rootCause.getCause() != null) {
99+
if (rootCause instanceof IllegalStateException) {
100+
break;
101+
}
102+
rootCause = rootCause.getCause();
103+
}
104+
return Assertions.assertThat(rootCause.getMessage());
105+
}
106+
}
107107
}
108108

109109
@Override
110110
public void close() {
111-
if (formatter instanceof FormatterFunc.Closeable) {
112-
((FormatterFunc.Closeable) formatter).close();
113-
}
111+
formatter.close();
114112
}
115113
}

0 commit comments

Comments
 (0)