diff --git a/CHANGES.md b/CHANGES.md
index 45fd5181fb..865f982128 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -13,6 +13,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
### Added
* Support for google-java-format 1.8 (including test infrastructure for Java 11). ([#562](https://github.com/diffplug/spotless/issues/562))
* Improved PaddedCell such that it is as performant as non-padded cell - no reason not to have it always enabled. Deprecated all of `PaddedCellBulk`. ([#561](https://github.com/diffplug/spotless/pull/561))
+* Support for ktfmt 0.13 ([#569](https://github.com/diffplug/spotless/pull/569))
### Changed
* Updated a bunch of dependencies, most notably: ([#564](https://github.com/diffplug/spotless/pull/564))
* jgit `5.5.0.201909110433-r` -> `5.7.0.202003110725-r`
diff --git a/README.md b/README.md
index a835e58e2c..c1c795f9c0 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ lib('java.ImportOrderStep') +'{{yes}} | {{yes}}
lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}} | {{no}} |',
extra('java.EclipseFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{no}} |',
+lib('kotlin.KtfmtStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('markdown.FreshMarkStep') +'{{yes}} | {{no}} | {{no}} |',
lib('npm.PrettierFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
lib('npm.TsFmtFormatterStep') +'{{yes}} | {{yes}} | {{no}} |',
@@ -73,6 +74,7 @@ extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}}
| [`java.RemoveUnusedImportsStep`](lib/src/main/java/com/diffplug/spotless/java/RemoveUnusedImportsStep.java) | :+1: | :+1: | :white_large_square: |
| [`java.EclipseFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseFormatterStep.java) | :+1: | :+1: | :white_large_square: |
| [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :white_large_square: |
+| [`kotlin.KtfmtStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java) | :+1: | :+1: | :white_large_square: |
| [`markdown.FreshMarkStep`](lib/src/main/java/com/diffplug/spotless/markdown/FreshMarkStep.java) | :+1: | :white_large_square: | :white_large_square: |
| [`npm.PrettierFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/PrettierFormatterStep.java) | :+1: | :+1: | :white_large_square: |
| [`npm.TsFmtFormatterStep`](lib/src/main/java/com/diffplug/spotless/npm/TsFmtFormatterStep.java) | :+1: | :+1: | :white_large_square: |
diff --git a/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
new file mode 100644
index 0000000000..58d6503ee1
--- /dev/null
+++ b/lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 DiffPlug
+ *
+ * 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
+ *
+ * http://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 com.diffplug.spotless.kotlin;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+import com.diffplug.spotless.*;
+
+/** Wraps up [ktfmt](https://github.com/facebookincubator/ktfmt) as a FormatterStep. */
+public class KtfmtStep {
+ // prevent direct instantiation
+ private KtfmtStep() {}
+
+ private static final String DEFAULT_VERSION = "0.13";
+ static final String NAME = "ktfmt";
+ static final String PACKAGE = "com.facebook";
+ static final String MAVEN_COORDINATE = PACKAGE + ":ktfmt:";
+
+ /**
+ * The format
method is available in the link below.
+ *
+ * @see:
+ * https://github.com/facebookincubator/ktfmt/blob/master/core/src/main/java/com/facebook/ktfmt/Formatter.kt#L61-L65
+ */
+ static final String FORMATTER_METHOD = "format";
+
+ /** Creates a step which formats everything - code, import order, and unused imports. */
+ public static FormatterStep create(Provisioner provisioner) {
+ return create(defaultVersion(), provisioner);
+ }
+
+ /** Creates a step which formats everything - code, import order, and unused imports. */
+ public static FormatterStep create(String version, Provisioner provisioner) {
+ Objects.requireNonNull(version, "version");
+ Objects.requireNonNull(provisioner, "provisioner");
+ return FormatterStep.createLazy(
+ NAME, () -> new State(version, provisioner), State::createFormat);
+ }
+
+ public static String defaultVersion() {
+ return DEFAULT_VERSION;
+ }
+
+ static final class State implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final String pkg;
+ /** The jar that contains the eclipse formatter. */
+ final JarState jarState;
+
+ State(String version, Provisioner provisioner) throws IOException {
+ this.pkg = PACKAGE;
+ this.jarState = JarState.from(MAVEN_COORDINATE + version, provisioner);
+ }
+
+ FormatterFunc createFormat() throws Exception {
+ ClassLoader classLoader = jarState.getClassLoader();
+
+ Class> formatterClazz = classLoader.loadClass(pkg + ".ktfmt.FormatterKt");
+ Method formatterMethod = formatterClazz.getMethod(FORMATTER_METHOD, String.class);
+
+ return input -> {
+ try {
+ return (String) formatterMethod.invoke(formatterClazz, input);
+ } catch (InvocationTargetException e) {
+ throw ThrowingEx.unwrapCause(e);
+ }
+ };
+ }
+ }
+}
diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md
index d9695a82ae..ed76d0a43b 100644
--- a/plugin-gradle/CHANGES.md
+++ b/plugin-gradle/CHANGES.md
@@ -5,7 +5,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Added
* [**VS Code Extension**](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle) thanks to [@badsyntax](https://github.com/badsyntax)
-* Support for google-java-format 1.8 (requires you to run build on Java 11) ([#562](https://github.com/diffplug/spotless/issues/562))
+* Support for google-java-format 1.8 (requires build to run on Java 11+) ([#562](https://github.com/diffplug/spotless/issues/562))
+* Support for ktfmt 0.13 (requires build to run on Java 11+) ([#569](https://github.com/diffplug/spotless/pull/569))
### Changed
* PaddedCell is now always enabled. It is strictly better than non-padded cell, and there is no performance penalty. [See here](https://github.com/diffplug/spotless/pull/560#issuecomment-621752798) for detailed explanation. ([#561](https://github.com/diffplug/spotless/pull/561))
* Updated a bunch of dependencies, most notably jgit `5.5.0.201909110433-r` -> `5.7.0.202003110725-r`. ([#564](https://github.com/diffplug/spotless/pull/564))
diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md
index ebe9e958d8..dfa96243b0 100644
--- a/plugin-gradle/README.md
+++ b/plugin-gradle/README.md
@@ -84,6 +84,7 @@ Spotless can check and apply formatting to any plain-text file, using simple rul
* [Groovy Eclipse](#groovy-eclipse)'s groovy code formatter
* [FreshMark](https://github.com/diffplug/freshmark) (markdown with variables)
* [ktlint](https://github.com/pinterest/ktlint)
+* [ktfmt](https://github.com/facebookincubator/ktfmt)
* [scalafmt](https://github.com/olafurpg/scalafmt)
* [DBeaver sql format](https://dbeaver.jkiss.org/)
* [Prettier: An opinionated code formatter](https://prettier.io)
@@ -278,6 +279,23 @@ spotless {
}
```
+
+
+## Applying [ktfmt](https://github.com/facebookincubator/ktfmt) to Kotlin files
+
+```gradle
+spotless {
+ kotlin {
+ // optionally takes a version
+ ktfmt()
+
+ // also supports license headers
+ licenseHeader '/* Licensed under Apache-2.0 */' // License header
+ licenseHeaderFile 'path-to-license-file' // License header file
+ }
+}
+```
+
## Applying [DBeaver](https://dbeaver.jkiss.org/) to SQL scripts
diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java
index 38e0dab504..0feacb8575 100644
--- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java
+++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java
@@ -28,6 +28,7 @@
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.kotlin.KtLintStep;
+import com.diffplug.spotless.kotlin.KtfmtStep;
public class KotlinExtension extends FormatExtension implements HasBuiltinDelimiterForLicense {
static final String NAME = "kotlin";
@@ -79,6 +80,33 @@ private FormatterStep createStep() {
}
}
+ /** Uses the [ktfmt](https://github.com/facebookincubator/ktfmt) jar to format source code. */
+ public KtfmtConfig ktfmt() {
+ return ktfmt(KtfmtStep.defaultVersion());
+ }
+
+ /**
+ * Uses the given version of [ktfmt](https://github.com/facebookincubator/ktfmt) to format source
+ * code.
+ */
+ public KtfmtConfig ktfmt(String version) {
+ Objects.requireNonNull(version);
+ return new KtfmtConfig(version);
+ }
+
+ public class KtfmtConfig {
+ final String version;
+
+ KtfmtConfig(String version) {
+ this.version = Objects.requireNonNull(version);
+ addStep(createStep());
+ }
+
+ private FormatterStep createStep() {
+ return KtfmtStep.create(version, GradleProvisioner.fromProject(getProject()));
+ }
+ }
+
/** If the user hasn't specified the files yet, we'll assume he/she means all of the kotlin files. */
@Override
protected void setupTask(SpotlessTask task) {
diff --git a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
index 82a3ef1f96..e1661e1ee2 100644
--- a/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
+++ b/plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java
@@ -23,6 +23,8 @@
import org.gradle.testkit.runner.BuildResult;
import org.junit.Test;
+import com.diffplug.spotless.JreVersion;
+
public class KotlinExtensionTest extends GradleIntegrationTest {
private static final String HEADER = "// License Header";
private static final String HEADER_WITH_YEAR = "// License Header $YEAR";
@@ -45,6 +47,28 @@ public void integration() throws IOException {
assertFile("src/main/kotlin/basic.kt").sameAsResource("kotlin/ktlint/basic.clean");
}
+ @Test
+ public void integrationKtfmt() throws IOException {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+ setFile("build.gradle").toLines(
+ "plugins {",
+ " id 'nebula.kotlin' version '1.0.6'",
+ " id 'com.diffplug.gradle.spotless'",
+ "}",
+ "repositories { mavenCentral() }",
+ "spotless {",
+ " kotlin {",
+ " ktfmt()",
+ " }",
+ "}");
+ setFile("src/main/kotlin/basic.kt").toResource("kotlin/ktfmt/basic.dirty");
+ gradleRunner().withArguments("spotlessApply").build();
+ assertFile("src/main/kotlin/basic.kt").sameAsResource("kotlin/ktfmt/basic.clean");
+ }
+
@Test
public void testWithIndentation() throws IOException {
setFile("build.gradle").toLines(
@@ -82,6 +106,29 @@ public void testWithHeader() throws IOException {
assertFile("src/main/kotlin/test.kt").hasContent(HEADER + "\n" + getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test"));
}
+ @Test
+ public void testWithHeaderKtfmt() throws IOException {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+ setFile("build.gradle").toLines(
+ "plugins {",
+ " id 'nebula.kotlin' version '1.0.6'",
+ " id 'com.diffplug.gradle.spotless'",
+ "}",
+ "repositories { mavenCentral() }",
+ "spotless {",
+ " kotlin {",
+ " licenseHeader('" + HEADER + "')",
+ " ktfmt()",
+ " }",
+ "}");
+ setFile("src/main/kotlin/test.kt").toResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test");
+ gradleRunner().withArguments("spotlessApply").build();
+ assertFile("src/main/kotlin/test.kt").hasContent(HEADER + "\n" + getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeaderKtfmt.test"));
+ }
+
@Test
public void testWithCustomHeaderSeparator() throws IOException {
setFile("build.gradle").toLines(
@@ -101,6 +148,29 @@ public void testWithCustomHeaderSeparator() throws IOException {
assertFile("src/main/kotlin/test.kt").hasContent(HEADER + "\n" + getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test"));
}
+ @Test
+ public void testWithCustomHeaderSeparatorKtfmt() throws IOException {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+ setFile("build.gradle").toLines(
+ "plugins {",
+ " id 'nebula.kotlin' version '1.0.6'",
+ " id 'com.diffplug.gradle.spotless'",
+ "}",
+ "repositories { mavenCentral() }",
+ "spotless {",
+ " kotlin {",
+ " licenseHeader ('" + HEADER + "', '@file')",
+ " ktfmt()",
+ " }",
+ "}");
+ setFile("src/main/kotlin/test.kt").toResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test");
+ gradleRunner().withArguments("spotlessApply").build();
+ assertFile("src/main/kotlin/test.kt").hasContent(HEADER + "\n" + getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeaderKtfmt.test"));
+ }
+
@Test
public void testWithNonStandardYearSeparator() throws IOException {
setFile("build.gradle").toLines(
@@ -126,4 +196,34 @@ public void testWithNonStandardYearSeparator() throws IOException {
matcher.startsWith(HEADER_WITH_YEAR.replace("$YEAR", String.valueOf(YearMonth.now().getYear())));
});
}
+
+ @Test
+ public void testWithNonStandardYearSeparatorKtfmt() throws IOException {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+ setFile("build.gradle").toLines(
+ "plugins {",
+ " id 'nebula.kotlin' version '1.0.6'",
+ " id 'com.diffplug.gradle.spotless'",
+ "}",
+ "repositories { mavenCentral() }",
+ "spotless {",
+ " kotlin {",
+ " licenseHeader('" + HEADER_WITH_YEAR + "').yearSeparator(', ')",
+ " ktfmt()",
+ " }",
+ "}");
+
+ setFile("src/main/kotlin/test.kt").toResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader.test");
+ setFile("src/main/kotlin/test2.kt").toResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader2.test");
+ gradleRunner().withArguments("spotlessApply").build();
+ assertFile("src/main/kotlin/test.kt").matches(matcher -> {
+ matcher.startsWith("// License Header 2012, 2014");
+ });
+ assertFile("src/main/kotlin/test2.kt").matches(matcher -> {
+ matcher.startsWith(HEADER_WITH_YEAR.replace("$YEAR", String.valueOf(YearMonth.now().getYear())));
+ });
+ }
}
diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md
index 502f16d7c8..744cec81e1 100644
--- a/plugin-maven/CHANGES.md
+++ b/plugin-maven/CHANGES.md
@@ -4,7 +4,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
## [Unreleased]
### Added
-* Support for google-java-format 1.8 (requires you to run build on Java 11) ([#562](https://github.com/diffplug/spotless/issues/562))
+* Support for google-java-format 1.8 (requires build to run on Java 11+) ([#562](https://github.com/diffplug/spotless/issues/562))
+* Support for ktfmt 0.13 (requires build to run on Java 11+) ([#569](https://github.com/diffplug/spotless/pull/569))
* `mvn spotless:apply` is now guaranteed to be idempotent, even if some of the formatters are not. See [`PADDEDCELL.md` for details](https://github.com/diffplug/spotless/blob/master/PADDEDCELL.md) if you're curious. ([#565](https://github.com/diffplug/spotless/pull/565))
* Updated a bunch of dependencies, most notably jgit `5.5.0.201909110433-r` -> `5.7.0.202003110725-r`. ([#564](https://github.com/diffplug/spotless/pull/564))
diff --git a/plugin-maven/README.md b/plugin-maven/README.md
index 34610ea2bd..517f51e527 100644
--- a/plugin-maven/README.md
+++ b/plugin-maven/README.md
@@ -153,6 +153,8 @@ By default, all files matching `src/main/scala/**/*.scala`, `src/test/scala/**/*
By default, all files matching `src/main/kotlin/**/*.kt` and `src/test/kotlin/**/*.kt` Ant style pattern will be formatted. Each element under `` is a step, and they will be applied in the order specified. Every step is optional.
+### Applying [ktlint](https://github.com/pinterest/ktlint) to Kotlin files
+
```xml
@@ -171,6 +173,26 @@ By default, all files matching `src/main/kotlin/**/*.kt` and `src/test/kotlin/**
```
+### Applying [ktfmt](https://github.com/facebookincubator/ktfmt) to Kotlin files
+
+```xml
+
+
+
+
+ /* Licensed under Apache-2.0 */
+ ${basedir}/license-header
+
+
+
+
+
+ 0.11
+
+
+
+```
+
## Applying to C/C++ source
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
index 51618613a4..dcfce10fc4 100644
--- a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Kotlin.java
@@ -39,4 +39,8 @@ public String licenseHeaderDelimiter() {
public void addKtlint(Ktlint ktlint) {
addStepFactory(ktlint);
}
+
+ public void addKtfmt(Ktfmt ktfmt) {
+ addStepFactory(ktfmt);
+ }
}
diff --git a/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java
new file mode 100644
index 0000000000..a5d99f81f4
--- /dev/null
+++ b/plugin-maven/src/main/java/com/diffplug/spotless/maven/kotlin/Ktfmt.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 DiffPlug
+ *
+ * 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
+ *
+ * http://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 com.diffplug.spotless.maven.kotlin;
+
+import org.apache.maven.plugins.annotations.Parameter;
+
+import com.diffplug.spotless.FormatterStep;
+import com.diffplug.spotless.kotlin.KtfmtStep;
+import com.diffplug.spotless.maven.FormatterStepConfig;
+import com.diffplug.spotless.maven.FormatterStepFactory;
+
+public class Ktfmt implements FormatterStepFactory {
+
+ @Parameter
+ private String version;
+
+ @Override
+ public FormatterStep newFormatterStep(FormatterStepConfig config) {
+ String version = this.version != null ? this.version : KtfmtStep.defaultVersion();
+ return KtfmtStep.create(version, config.getProvisioner());
+ }
+}
diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java
new file mode 100644
index 0000000000..d87c15a503
--- /dev/null
+++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/kotlin/KtfmtTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 DiffPlug
+ *
+ * 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
+ *
+ * http://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 com.diffplug.spotless.maven.kotlin;
+
+import org.junit.Test;
+
+import com.diffplug.spotless.JreVersion;
+import com.diffplug.spotless.maven.MavenIntegrationTest;
+
+public class KtfmtTest extends MavenIntegrationTest {
+ @Test
+ public void testKtfmt() throws Exception {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+
+ writePomWithKotlinSteps("");
+
+ String path1 = "src/main/kotlin/main1.kt";
+ String path2 = "src/main/kotlin/main2.kt";
+
+ setFile(path1).toResource("kotlin/ktfmt/basic.dirty");
+ setFile(path2).toResource("kotlin/ktfmt/basic.dirty");
+
+ mavenRunner().withArguments("spotless:apply").runNoError();
+
+ assertFile(path1).sameAsResource("kotlin/ktfmt/basic.clean");
+ assertFile(path2).sameAsResource("kotlin/ktfmt/basic.clean");
+ }
+}
diff --git a/testlib/src/main/resources/kotlin/ktfmt/basic.clean b/testlib/src/main/resources/kotlin/ktfmt/basic.clean
new file mode 100644
index 0000000000..668c9bd20d
--- /dev/null
+++ b/testlib/src/main/resources/kotlin/ktfmt/basic.clean
@@ -0,0 +1,13 @@
+import a.*
+import a.b
+import a.b.c.*
+import kotlinx.android.synthetic.main.layout_name.*
+
+fun main() {
+ fun name() {
+ a();
+ return b
+ }
+ println(";")
+ println();
+}
diff --git a/testlib/src/main/resources/kotlin/ktfmt/basic.dirty b/testlib/src/main/resources/kotlin/ktfmt/basic.dirty
new file mode 100644
index 0000000000..1a76f25fcc
--- /dev/null
+++ b/testlib/src/main/resources/kotlin/ktfmt/basic.dirty
@@ -0,0 +1,12 @@
+import a.*
+
+import kotlinx.android.synthetic.main.layout_name.*
+
+import a.b.c.*
+import a.b
+
+fun main() {
+ fun name() { a(); return b }
+ println(";")
+ println();
+}
diff --git a/testlib/src/main/resources/kotlin/licenseheader/KotlinCodeWithoutHeaderKtfmt.test b/testlib/src/main/resources/kotlin/licenseheader/KotlinCodeWithoutHeaderKtfmt.test
new file mode 100644
index 0000000000..16ba57b2d4
--- /dev/null
+++ b/testlib/src/main/resources/kotlin/licenseheader/KotlinCodeWithoutHeaderKtfmt.test
@@ -0,0 +1,5 @@
+@file:JvmName("SomeFileName")
+
+package my.test
+
+object AnObject
diff --git a/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java
new file mode 100644
index 0000000000..602ddc5dae
--- /dev/null
+++ b/testlib/src/test/java/com/diffplug/spotless/kotlin/KtfmtStepTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 DiffPlug
+ *
+ * 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
+ *
+ * http://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 com.diffplug.spotless.kotlin;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.diffplug.spotless.*;
+
+@Ignore
+public class KtfmtStepTest extends ResourceHarness {
+ @Test
+ public void behavior() throws Exception {
+ if (JreVersion.thisVm() == JreVersion._8) {
+ // ktfmt's dependency, google-java-format 1.8 requires a minimum of JRE 11+.
+ return;
+ }
+ FormatterStep step = KtfmtStep.create(TestProvisioner.mavenCentral());
+ StepHarness.forStep(step).testResource("kotlin/ktfmt/basic.dirty", "kotlin/ktfmt/basic.clean");
+ }
+
+ @Test
+ public void equality() throws Exception {
+ new SerializableEqualityTester() {
+ String version = "0.13";
+
+ @Override
+ protected void setupTest(API api) {
+ // same version == same
+ api.areDifferentThan();
+ // change the version, and it's different
+ version = "0.12";
+ api.areDifferentThan();
+ }
+
+ @Override
+ protected FormatterStep create() {
+ String finalVersion = this.version;
+ return KtfmtStep.create(finalVersion, TestProvisioner.mavenCentral());
+ }
+ }.testEquals();
+ }
+}