Skip to content

Fixup the last of the stragglers #2146

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/src/main/java/com/diffplug/spotless/Formatter.java
Original file line number Diff line number Diff line change
@@ -312,4 +312,10 @@ public void close() {

/** This Sentinel reference may be used to pass string content to a Formatter or FormatterStep when there is no actual File to format */
public static final File NO_FILE_SENTINEL = new File("NO_FILE_SENTINEL");

static void checkNotSentinel(File file) {
if (file == Formatter.NO_FILE_SENTINEL) {
throw new IllegalArgumentException("This step requires the underlying file. If this is a test, use StepHarnessWithFile");
}
}
}
4 changes: 2 additions & 2 deletions lib/src/main/java/com/diffplug/spotless/FormatterFunc.java
Original file line number Diff line number Diff line change
@@ -115,7 +115,7 @@ public void close() {

@Override
public String apply(String unix, File file) throws Exception {
FormatterStepImpl.checkNotSentinel(file);
Formatter.checkNotSentinel(file);
return function.apply(resource, unix, file);
}

@@ -144,7 +144,7 @@ interface NeedsFile extends FormatterFunc {

@Override
default String apply(String unix, File file) throws Exception {
FormatterStepImpl.checkNotSentinel(file);
Formatter.checkNotSentinel(file);
return applyWithFile(unix, file);
}

28 changes: 3 additions & 25 deletions lib/src/main/java/com/diffplug/spotless/FormatterStep.java
Original file line number Diff line number Diff line change
@@ -70,28 +70,6 @@ default FormatterStep filterByFile(SerializableFileFilter filter) {
return new FilterByFileFormatterStep(this, filter);
}

/**
* Implements a FormatterStep in a strict way which guarantees correct and lazy implementation
* of up-to-date checks. This maximizes performance for cases where the FormatterStep is not
* actually needed (e.g. don't load eclipse setting file unless this step is actually running)
* while also ensuring that Gradle can detect changes in a step's settings to determine that
* it needs to rerun a format.
*/
abstract class Strict<State extends Serializable> extends LazyForwardingEquality<State> implements FormatterStep {
private static final long serialVersionUID = 1L;

/**
* Implements the formatting function strictly in terms
* of the input data and the result of {@link #calculateState()}.
*/
protected abstract String format(State state, String rawUnix, File file) throws Exception;

@Override
public final String format(String rawUnix, File file) throws Exception {
return format(state(), rawUnix, file);
}
}

/**
* @param name
* The name of the formatter step.
@@ -151,8 +129,8 @@ static <RoundtripState extends Serializable, EqualityState extends Serializable>
static <State extends Serializable> FormatterStep createLazy(
String name,
ThrowingEx.Supplier<State> stateSupplier,
ThrowingEx.Function<State, FormatterFunc> stateToFormatter) {
return new FormatterStepImpl.Standard<>(name, stateSupplier, stateToFormatter);
SerializedFunction<State, FormatterFunc> stateToFormatter) {
return createLazy(name, stateSupplier, SerializedFunction.identity(), stateToFormatter);
}

/**
@@ -168,7 +146,7 @@ static <State extends Serializable> FormatterStep createLazy(
static <State extends Serializable> FormatterStep create(
String name,
State state,
ThrowingEx.Function<State, FormatterFunc> stateToFormatter) {
SerializedFunction<State, FormatterFunc> stateToFormatter) {
Objects.requireNonNull(state, "state");
return createLazy(name, () -> state, stateToFormatter);
}
133 changes: 0 additions & 133 deletions lib/src/main/java/com/diffplug/spotless/FormatterStepImpl.java

This file was deleted.

12 changes: 6 additions & 6 deletions lib/src/main/java/com/diffplug/spotless/cpp/ClangFormatStep.java
Original file line number Diff line number Diff line change
@@ -64,10 +64,10 @@ public ClangFormatStep withPathToExe(String pathToExe) {
}

public FormatterStep create() {
return FormatterStep.createLazy(name(), this::createState, RoundtripState::state, State::toFunc);
return FormatterStep.createLazy(name(), this::createRoundtrip, RoundtripState::toEquality, EqualityState::toFunc);
}

private RoundtripState createState() throws IOException, InterruptedException {
private RoundtripState createRoundtrip() throws IOException, InterruptedException {
String howToInstall = "" +
"You can download clang-format from https://releases.llvm.org and " +
"then point Spotless to it with {@code pathToExe('/path/to/clang-format')} " +
@@ -98,13 +98,13 @@ static class RoundtripState implements Serializable {
this.exe = exe;
}

private State state() {
return new State(version, style, exe);
private EqualityState toEquality() {
return new EqualityState(version, style, exe);
}
}

@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
static class State implements Serializable {
static class EqualityState implements Serializable {
private static final long serialVersionUID = -1825662356883926318L;
// used for up-to-date checks and caching
final String version;
@@ -113,7 +113,7 @@ static class State implements Serializable {
// used for executing
private transient @Nullable List<String> args;

State(String version, @Nullable String style, ForeignExe pathToExe) {
EqualityState(String version, @Nullable String style, ForeignExe pathToExe) {
this.version = version;
this.style = style;
this.exe = Objects.requireNonNull(pathToExe);
25 changes: 19 additions & 6 deletions lib/src/main/java/com/diffplug/spotless/generic/NativeCmdStep.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 DiffPlug
* Copyright 2021-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,24 +35,37 @@ private NativeCmdStep() {}
public static FormatterStep create(String name, File pathToExe, List<String> arguments) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(pathToExe, "pathToExe");
return FormatterStep.createLazy(name, () -> new State(FileSignature.signAsList(pathToExe), arguments), State::toFunc);
return FormatterStep.createLazy(name, () -> new State(FileSignature.promise(pathToExe), arguments), State::toRuntime, Runtime::toFunc);
}

static class State implements Serializable {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 2L;
final FileSignature.Promised pathToExe;
final List<String> arguments;

final FileSignature pathToExe;
State(FileSignature.Promised pathToExe, List<String> arguments) {
this.pathToExe = pathToExe;
this.arguments = arguments;
}

Runtime toRuntime() {
return new Runtime(pathToExe.get().getOnlyFile(), arguments);
}
}

static class Runtime implements Serializable {
private static final long serialVersionUID = 2L;
final File pathToExe;
final List<String> arguments;

State(FileSignature pathToExe, List<String> arguments) {
Runtime(File pathToExe, List<String> arguments) {
this.pathToExe = pathToExe;
this.arguments = arguments;
}

String format(ProcessRunner runner, String input) throws IOException, InterruptedException {
List<String> argumentsWithPathToExe = new ArrayList<>();
argumentsWithPathToExe.add(pathToExe.getOnlyFile().getAbsolutePath());
argumentsWithPathToExe.add(pathToExe.getAbsolutePath());
if (arguments != null) {
argumentsWithPathToExe.addAll(arguments);
}
28 changes: 22 additions & 6 deletions lib/src/main/java/com/diffplug/spotless/go/GofmtFormatStep.java
Original file line number Diff line number Diff line change
@@ -63,10 +63,10 @@ public GofmtFormatStep withGoExecutable(String pathToExe) {
}

public FormatterStep create() {
return FormatterStep.createLazy(name(), this::createState, GofmtFormatStep.State::toFunc);
return FormatterStep.createLazy(name(), this::createRountrip, RoundtripState::toEquality, EqualityState::toFunc);
}

private State createState() throws IOException, InterruptedException {
private RoundtripState createRountrip() throws IOException, InterruptedException {
String howToInstall = "gofmt is a part of standard go distribution. If spotless can't discover it automatically, " +
"you can point Spotless to the go binary with {@code pathToExe('/path/to/go')}";
final ForeignExe exe = ForeignExe.nameAndVersion("go", version)
@@ -76,18 +76,34 @@ private State createState() throws IOException, InterruptedException {
.fixWrongVersion(
"You can tell Spotless to use the version you already have with {@code gofmt('{versionFound}')}" +
"or you can install the currently specified Go version, {version}.\n" + howToInstall);
return new State(this, exe);
return new RoundtripState(version, exe);
}

static class RoundtripState implements Serializable {
private static final long serialVersionUID = 1L;

final String version;
final ForeignExe exe;

RoundtripState(String version, ForeignExe exe) {
this.version = version;
this.exe = exe;
}

private EqualityState toEquality() {
return new EqualityState(version, exe);
}
}

@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
static class State implements Serializable {
static class EqualityState implements Serializable {
private static final long serialVersionUID = -1825662355363926318L;
// used for up-to-date checks and caching
final String version;
final transient ForeignExe exe;

public State(GofmtFormatStep step, ForeignExe goExecutable) {
this.version = step.version;
public EqualityState(String version, ForeignExe goExecutable) {
this.version = version;
this.exe = Objects.requireNonNull(goExecutable);
}

12 changes: 6 additions & 6 deletions lib/src/main/java/com/diffplug/spotless/python/BlackStep.java
Original file line number Diff line number Diff line change
@@ -56,10 +56,10 @@ public BlackStep withPathToExe(String pathToExe) {
}

public FormatterStep create() {
return FormatterStep.createLazy(name(), this::createState, RoundtripState::state, State::toFunc);
return FormatterStep.createLazy(name(), this::createRoundtrip, RoundtripState::toEquality, EqualityState::toFunc);
}

private RoundtripState createState() {
private RoundtripState createRoundtrip() {
String trackingIssue = "\n github issue to handle this better: https://github.com/diffplug/spotless/issues/674";
ForeignExe exeAbsPath = ForeignExe.nameAndVersion("black", version)
.pathToExe(pathToExe)
@@ -80,21 +80,21 @@ static class RoundtripState implements Serializable {
this.exe = exe;
}

private State state() {
return new State(version, exe);
private EqualityState toEquality() {
return new EqualityState(version, exe);
}
}

@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
static class State implements Serializable {
static class EqualityState implements Serializable {
private static final long serialVersionUID = -1825662356883926318L;
// used for up-to-date checks and caching
final String version;
final transient ForeignExe exe;
// used for executing
private transient @Nullable String[] args;

State(String version, ForeignExe exeAbsPath) {
EqualityState(String version, ForeignExe exeAbsPath) {
this.version = version;
this.exe = Objects.requireNonNull(exeAbsPath);
}
28 changes: 22 additions & 6 deletions lib/src/main/java/com/diffplug/spotless/shell/ShfmtStep.java
Original file line number Diff line number Diff line change
@@ -60,10 +60,10 @@ public ShfmtStep withPathToExe(String pathToExe) {
}

public FormatterStep create() {
return FormatterStep.createLazy(name(), this::createState, State::toFunc);
return FormatterStep.createLazy(name(), this::createRoundtrip, RoundtripState::toEquality, EqualityState::toFunc);
}

private State createState() throws IOException, InterruptedException {
private RoundtripState createRoundtrip() throws IOException, InterruptedException {
String howToInstall = "" +
"You can download shfmt from https://github.com/mvdan/sh and " +
"then point Spotless to it with {@code pathToExe('/path/to/shfmt')} " +
@@ -79,11 +79,27 @@ private State createState() throws IOException, InterruptedException {
.fixWrongVersion(
"You can tell Spotless to use the version you already have with {@code shfmt('{versionFound}')}" +
"or you can download the currently specified version, {version}.\n" + howToInstall);
return new State(this, exe);
return new RoundtripState(version, exe);
}

static class RoundtripState implements Serializable {
private static final long serialVersionUID = 1L;

final String version;
final ForeignExe exe;

RoundtripState(String version, ForeignExe exe) {
this.version = version;
this.exe = exe;
}

private EqualityState toEquality() {
return new EqualityState(version, exe);
}
}

@SuppressFBWarnings("SE_TRANSIENT_FIELD_NOT_RESTORED")
static class State implements Serializable {
static class EqualityState implements Serializable {
private static final long serialVersionUID = -1825662356883926318L;

// used for up-to-date checks and caching
@@ -93,8 +109,8 @@ static class State implements Serializable {
// used for executing
private transient @Nullable List<String> args;

State(ShfmtStep step, ForeignExe pathToExe) {
this.version = step.version;
EqualityState(String version, ForeignExe pathToExe) {
this.version = version;
this.exe = Objects.requireNonNull(pathToExe);
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package com.diffplug.spotless.sql;

import java.io.File;
import java.io.Serializable;

import com.diffplug.spotless.FileSignature;
import com.diffplug.spotless.FormatterFunc;
@@ -32,24 +31,14 @@ public class DBeaverSQLFormatterStep {
private DBeaverSQLFormatterStep() {}

public static FormatterStep create(Iterable<File> files) {
return FormatterStep.createLazy(NAME,
() -> new State(files),
State::createFormat);
return FormatterStep.create(NAME, FileSignature.promise(files),
FileSignature.Promised::get,
DBeaverSQLFormatterStep::createFormat);
}

static final class State implements Serializable {
private static final long serialVersionUID = 1L;

final FileSignature settingsSignature;

State(final Iterable<File> settingsFiles) throws Exception {
this.settingsSignature = FileSignature.signAsList(settingsFiles);
}

FormatterFunc createFormat() throws Exception {
FormatterProperties preferences = FormatterProperties.from(settingsSignature.files());
DBeaverSQLFormatter dbeaverSqlFormatter = new DBeaverSQLFormatter(preferences.getProperties());
return dbeaverSqlFormatter::format;
}
private static FormatterFunc createFormat(FileSignature settings) {
FormatterProperties preferences = FormatterProperties.from(settings.files());
DBeaverSQLFormatter dbeaverSqlFormatter = new DBeaverSQLFormatter(preferences.getProperties());
return dbeaverSqlFormatter::format;
}
}
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (

## [Unreleased]
### Added
* Full, no-asterisk support of Gradle configuration cache. ([#1274](https://github.com/diffplug/spotless/issues/1274), giving up on [#987](https://github.com/diffplug/spotless/issues/987))
* In order to use `custom`, you must now use Gradle 8.0+.
* Respect `.editorconfig` settings for formatting shell via `shfmt` ([#2031](https://github.com/diffplug/spotless/pull/2031))
* Add support for formatting and sorting Maven POMs ([#2082](https://github.com/diffplug/spotless/issues/2082))
### Fixed
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
package com.diffplug.gradle.spotless;

import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull;
import static com.diffplug.gradle.spotless.SpotlessPluginRedirect.badSemver;
import static java.util.Objects.requireNonNull;

import java.io.File;
@@ -451,6 +452,12 @@ public String apply(String unixNewlines) {
*/
public void custom(String name, FormatterFunc formatter) {
requireNonNull(formatter, "formatter");
if (badSemver(getProject()) < badSemver(SpotlessPlugin.VER_GRADLE_minVersionForCustom)) {
throw new GradleException("The 'custom' method is only available if you are using Gradle "
+ SpotlessPlugin.VER_GRADLE_minVersionForCustom
+ " or newer, this is "
+ getProject().getGradle().getGradleVersion());
}
addStep(FormatterStep.createLazy(name, () -> globalState, SerializedFunction.alwaysReturns(formatter)));
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ public class SpotlessPlugin implements Plugin<Project> {
static final String SPOTLESS_MODERN = "spotlessModern";
static final String VER_GRADLE_min = "6.1.1";
static final String VER_GRADLE_javaPluginExtension = "7.1";
static final String VER_GRADLE_minVersionForCustom = "8.0";
private static final int MINIMUM_JRE = 11;

@Override
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2023 DiffPlug
* Copyright 2020-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,11 @@
public class SpotlessPluginRedirect implements Plugin<Project> {
private static final Pattern BAD_SEMVER = Pattern.compile("(\\d+)\\.(\\d+)");

private static int badSemver(String input) {
static int badSemver(Project project) {
return badSemver(project.getGradle().getGradleVersion());
}

static int badSemver(String input) {
Matcher matcher = BAD_SEMVER.matcher(input);
if (!matcher.find() || matcher.start() != 0) {
throw new IllegalArgumentException("Version must start with " + BAD_SEMVER.pattern());
@@ -46,7 +50,7 @@ private static int badSemver(int major, int minor) {

static boolean gradleIsTooOld(Project project) {
if (gradleIsTooOld == null) {
gradleIsTooOld = badSemver(project.getGradle().getGradleVersion()) < badSemver(SpotlessPlugin.VER_GRADLE_min);
gradleIsTooOld = badSemver(project) < badSemver(SpotlessPlugin.VER_GRADLE_min);
}
return gradleIsTooOld.booleanValue();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
import org.junit.jupiter.api.Test;

class BumpThisNumberIfACustomStepChangesTest extends GradleIntegrationHarness {

private void writeBuildFile(String toInsert) throws IOException {
setFile("build.gradle").toLines(
"plugins {",
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ private Git initRepo() throws IllegalStateException, GitAPIException, IOExceptio

@Override
protected GradleRunner gradleRunner() throws IOException {
return super.gradleRunner().withGradleVersion(GradleVersionSupport.CONFIGURATION_CACHE.version);
return super.gradleRunner().withGradleVersion(GradleVersionSupport.CUSTOM_STEPS.version);
}

@ParameterizedTest
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@

public class GradleIntegrationHarness extends ResourceHarness {
public enum GradleVersionSupport {
JRE_11("5.0"), MINIMUM(SpotlessPlugin.VER_GRADLE_min),
JRE_11("5.0"), MINIMUM(SpotlessPlugin.VER_GRADLE_min), CUSTOM_STEPS(SpotlessPlugin.VER_GRADLE_minVersionForCustom),
// technically, this API exists in 6.5, but the flags for it change in 6.6, so we build to that
CONFIGURATION_CACHE("6.6"),
// https://docs.gradle.org/7.5/userguide/configuration_cache.html#config_cache:stable
@@ -116,8 +116,14 @@ void gitAttributes() throws IOException {
}

protected GradleRunner gradleRunner() throws IOException {
GradleVersionSupport version;
if (newFile("build.gradle").exists() && read("build.gradle").contains("custom")) {
version = GradleVersionSupport.CUSTOM_STEPS;
} else {
version = GradleVersionSupport.MINIMUM;
}
return GradleRunner.create()
.withGradleVersion(GradleVersionSupport.MINIMUM.version)
.withGradleVersion(version.version)
.withProjectDir(rootFolder())
.withTestKitDir(getTestKitDir())
.withPluginClasspath();
Original file line number Diff line number Diff line change
@@ -27,14 +27,15 @@ enum RoundTrip {
private final Formatter formatter;

protected StepHarnessBase(Formatter formatter, RoundTrip roundTrip) {
this.formatter = Objects.requireNonNull(formatter);
if (roundTrip == RoundTrip.DONT_ROUNDTRIP) {
this.formatter = Objects.requireNonNull(formatter);
return;
}
Formatter roundTripped = SerializableEqualityTester.reserialize(formatter);
if (roundTrip == RoundTrip.ASSERT_EQUAL) {
Assertions.assertThat(roundTripped).isEqualTo(formatter);
}
this.formatter = roundTripped;
}

protected Formatter formatter() {
Original file line number Diff line number Diff line change
@@ -16,16 +16,11 @@
package com.diffplug.spotless.generic;

import java.io.File;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;

import javax.annotation.Nullable;

import org.junit.jupiter.api.Test;

import com.diffplug.common.base.StringPrinter;
import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.ResourceHarness;
import com.diffplug.spotless.StepHarness;
@@ -34,8 +29,8 @@ class FenceStepTest extends ResourceHarness {
@Test
void single() {
FormatterStep fence = FenceStep.named("fence").openClose("spotless:off", "spotless:on")
.preserveWithin(Arrays.asList(createNeverUpToDateSerializable("lowercase", String::toLowerCase)));
StepHarness harness = StepHarness.forStepNoRoundtrip(fence);
.preserveWithin(Arrays.asList(ToCaseStep.lower()));
StepHarness harness = StepHarness.forStep(fence);
harness.test(
StringPrinter.buildStringFromLines(
"A B C",
@@ -54,8 +49,8 @@ void single() {
@Test
void multiple() {
FormatterStep fence = FenceStep.named("fence").openClose("spotless:off", "spotless:on")
.preserveWithin(Arrays.asList(createNeverUpToDateSerializable("lowercase", String::toLowerCase)));
StepHarness harness = StepHarness.forStepNoRoundtrip(fence);
.preserveWithin(Arrays.asList(ToCaseStep.lower()));
StepHarness harness = StepHarness.forStep(fence);
harness.test(
StringPrinter.buildStringFromLines(
"A B C",
@@ -88,7 +83,7 @@ void multiple() {
@Test
void broken() {
FormatterStep fence = FenceStep.named("fence").openClose("spotless:off", "spotless:on")
.preserveWithin(Arrays.asList(createNeverUpToDateSerializable("uppercase", String::toUpperCase)));
.preserveWithin(Arrays.asList(ToCaseStep.upper()));
// this fails because uppercase turns spotless:off into SPOTLESS:OFF, etc
StepHarness.forStepNoRoundtrip(fence).testExceptionMsg(StringPrinter.buildStringFromLines("A B C",
"spotless:off",
@@ -100,8 +95,8 @@ void broken() {
@Test
void andApply() {
FormatterStep fence = FenceStep.named("fence").openClose("<lower>", "</lower>")
.applyWithin(Arrays.asList(createNeverUpToDateSerializable("lowercase", String::toLowerCase)));
StepHarness.forStepNoRoundtrip(fence).test(
.applyWithin(Arrays.asList(ToCaseStep.lower()));
StepHarness.forStep(fence).test(
StringPrinter.buildStringFromLines(
"A B C",
"<lower>",
@@ -116,46 +111,45 @@ void andApply() {
"G H I"));
}

/**
* @param name
* The name of the formatter step
* @param function
* The function used by the formatter step
* @return A FormatterStep which will never report that it is up-to-date, because
* it is not equal to the serialized representation of itself.
*/
static <T extends FormatterFunc & Serializable> FormatterStep createNeverUpToDateSerializable(
String name,
T function) {
Objects.requireNonNull(function, "function");
return new NeverUpToDateSerializable(name, function);
}
static class ToCaseStep implements FormatterStep {
static ToCaseStep upper() {
return new ToCaseStep(true);
}

static class NeverUpToDateSerializable<T extends FormatterFunc & Serializable> implements FormatterStep, Serializable {
private final String name;
private final T formatterFunc;
static ToCaseStep lower() {
return new ToCaseStep(false);
}

private final boolean uppercase;

private NeverUpToDateSerializable(String name, T formatterFunc) {
this.name = name;
this.formatterFunc = formatterFunc;
ToCaseStep(boolean uppercase) {
this.uppercase = uppercase;
}

@Override
public String getName() {
return name;
return uppercase ? "uppercase" : "lowercase";
}

@Nullable
@org.jetbrains.annotations.Nullable
@Override
public String format(String rawUnix, File file) throws Exception {
return formatterFunc.apply(rawUnix, file);
return uppercase ? rawUnix.toUpperCase() : rawUnix.toLowerCase();
}

@Override
public void close() throws Exception {
if (formatterFunc instanceof FormatterFunc.Closeable) {
((FormatterFunc.Closeable) formatterFunc).close();
}

}

@Override
public int hashCode() {
return getName().hashCode();
}

@Override
public boolean equals(Object obj) {
return obj instanceof ToCaseStep && getName().equals(((ToCaseStep) obj).getName());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 DiffPlug
* Copyright 2016-2024 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
class DBeaverSQLFormatterStepTest extends ResourceHarness {

@Test
void behavior() throws Exception {
void behavior() {
FormatterStep step = DBeaverSQLFormatterStep.create(Collections.emptySet());
StepHarness.forStep(step)
.testResource("sql/dbeaver/full.dirty", "sql/dbeaver/full.clean")
@@ -40,21 +40,21 @@ void behavior() throws Exception {
}

@Test
void behaviorWithConfigFile() throws Exception {
void behaviorWithConfigFile() {
FormatterStep step = DBeaverSQLFormatterStep.create(createTestFiles("sql/dbeaver/sqlConfig.properties"));
StepHarness.forStep(step)
.testResource("sql/dbeaver/create.dirty", "sql/dbeaver/create.clean");
}

@Test
void behaviorWithAlternativeConfigFile() throws Exception {
void behaviorWithAlternativeConfigFile() {
FormatterStep step = DBeaverSQLFormatterStep.create(createTestFiles("sql/dbeaver/sqlConfig2.properties"));
StepHarness.forStep(step)
.testResource("sql/dbeaver/create.dirty", "sql/dbeaver/create.clean.alternative");
}

@Test
void equality() throws Exception {
void equality() {
List<File> sqlConfig1 = createTestFiles("sql/dbeaver/sqlConfig.properties");
List<File> sqlConfig2 = createTestFiles("sql/dbeaver/sqlConfig2.properties");
new SerializableEqualityTester() {