From 300e68b43ed6c3d4e9071b39f1670f4171625dc7 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Mon, 23 Jun 2025 22:09:19 +0200 Subject: [PATCH 01/18] Avoid empty body warnings emposed by default activation of expandEmptyElements --- lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 08a0308178..db37ae25fd 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 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,7 @@ public class SortPomCfg implements Serializable { public String lineSeparator = System.getProperty("line.separator"); - public boolean expandEmptyElements = true; + public boolean expandEmptyElements; public boolean spaceBeforeCloseEmptyElement = false; From c28863146e20a3e1be3bc7942c32cd5e7c898304 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 10:34:12 +0200 Subject: [PATCH 02/18] Avoid empty body warnings emposed by default activation of expandEmptyElements --- gradle.properties | 2 +- .../diffplug/spotless/pom/SortPomCfgTest.java | 160 ++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java diff --git a/gradle.properties b/gradle.properties index 15029d95ab..1ef2017082 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,7 +29,7 @@ VER_SLF4J=[1.6,2.0[ # Used in multiple places VER_DURIAN=1.2.0 VER_JGIT=6.10.1.202505221210-r -VER_JUNIT=5.13.0 +VER_JUNIT=5.13.1 VER_ASSERTJ=3.27.3 VER_MOCKITO=5.18.0 VER_SELFIE=2.5.3 \ No newline at end of file diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java new file mode 100644 index 0000000000..58f96ae1b7 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java @@ -0,0 +1,160 @@ +package com.diffplug.spotless.pom; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class SortPomCfgTest { + + @Test + void testDefaultValues() { + SortPomCfg cfg = new SortPomCfg(); + + // Test default values + assertEquals("4.0.0", cfg.version); + assertEquals("UTF-8", cfg.encoding); + assertEquals(System.getProperty("line.separator"), cfg.lineSeparator); + assertFalse(cfg.expandEmptyElements); + assertFalse(cfg.spaceBeforeCloseEmptyElement); + assertTrue(cfg.keepBlankLines); + assertTrue(cfg.endWithNewline); + assertEquals(2, cfg.nrOfIndentSpace); + assertFalse(cfg.indentBlankLines); + assertFalse(cfg.indentSchemaLocation); + assertNull(cfg.indentAttribute); + assertEquals("recommended_2008_06", cfg.predefinedSortOrder); + assertFalse(cfg.quiet); + assertNull(cfg.sortOrderFile); + assertNull(cfg.sortDependencies); + assertNull(cfg.sortDependencyManagement); + assertNull(cfg.sortDependencyExclusions); + assertNull(cfg.sortPlugins); + assertFalse(cfg.sortProperties); + assertFalse(cfg.sortModules); + assertFalse(cfg.sortExecutions); + } + + @Test + void testFieldSetters() { + SortPomCfg cfg = new SortPomCfg(); + + // Test setting all fields + cfg.version = "4.1.0"; + cfg.encoding = "ISO-8859-1"; + cfg.lineSeparator = "\n"; + cfg.expandEmptyElements = true; + cfg.spaceBeforeCloseEmptyElement = true; + cfg.keepBlankLines = false; + cfg.endWithNewline = false; + cfg.nrOfIndentSpace = 4; + cfg.indentBlankLines = true; + cfg.indentSchemaLocation = true; + cfg.indentAttribute = "attribute"; + cfg.predefinedSortOrder = "custom"; + cfg.quiet = true; + cfg.sortOrderFile = "sortOrder.xml"; + cfg.sortDependencies = "groupId,artifactId"; + cfg.sortDependencyManagement = "scope,groupId"; + cfg.sortDependencyExclusions = "artifactId"; + cfg.sortPlugins = "groupId"; + cfg.sortProperties = true; + cfg.sortModules = true; + cfg.sortExecutions = true; + + // Verify all set values + assertEquals("4.1.0", cfg.version); + assertEquals("ISO-8859-1", cfg.encoding); + assertEquals("\n", cfg.lineSeparator); + assertTrue(cfg.expandEmptyElements); + assertTrue(cfg.spaceBeforeCloseEmptyElement); + assertFalse(cfg.keepBlankLines); + assertFalse(cfg.endWithNewline); + assertEquals(4, cfg.nrOfIndentSpace); + assertTrue(cfg.indentBlankLines); + assertTrue(cfg.indentSchemaLocation); + assertEquals("attribute", cfg.indentAttribute); + assertEquals("custom", cfg.predefinedSortOrder); + assertTrue(cfg.quiet); + assertEquals("sortOrder.xml", cfg.sortOrderFile); + assertEquals("groupId,artifactId", cfg.sortDependencies); + assertEquals("scope,groupId", cfg.sortDependencyManagement); + assertEquals("artifactId", cfg.sortDependencyExclusions); + assertEquals("groupId", cfg.sortPlugins); + assertTrue(cfg.sortProperties); + assertTrue(cfg.sortModules); + assertTrue(cfg.sortExecutions); + } + + @Test + void testNullHandling() { + SortPomCfg cfg = new SortPomCfg(); + + // Test setting nullable fields to null + cfg.version = null; + cfg.encoding = null; + cfg.lineSeparator = null; + cfg.indentAttribute = null; + cfg.predefinedSortOrder = null; + cfg.sortOrderFile = null; + cfg.sortDependencies = null; + cfg.sortDependencyManagement = null; + cfg.sortDependencyExclusions = null; + cfg.sortPlugins = null; + + assertNull(cfg.version); + assertNull(cfg.encoding); + assertNull(cfg.lineSeparator); + assertNull(cfg.indentAttribute); + assertNull(cfg.predefinedSortOrder); + assertNull(cfg.sortOrderFile); + assertNull(cfg.sortDependencies); + assertNull(cfg.sortDependencyManagement); + assertNull(cfg.sortDependencyExclusions); + assertNull(cfg.sortPlugins); + } + + @Test + void testBooleanFieldsEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Verify all boolean fields can be toggled + cfg.expandEmptyElements = !cfg.expandEmptyElements; + cfg.spaceBeforeCloseEmptyElement = !cfg.spaceBeforeCloseEmptyElement; + cfg.keepBlankLines = !cfg.keepBlankLines; + cfg.endWithNewline = !cfg.endWithNewline; + cfg.indentBlankLines = !cfg.indentBlankLines; + cfg.indentSchemaLocation = !cfg.indentSchemaLocation; + cfg.quiet = !cfg.quiet; + cfg.sortProperties = !cfg.sortProperties; + cfg.sortModules = !cfg.sortModules; + cfg.sortExecutions = !cfg.sortExecutions; + + assertTrue(cfg.expandEmptyElements); + assertTrue(cfg.spaceBeforeCloseEmptyElement); + assertFalse(cfg.keepBlankLines); + assertFalse(cfg.endWithNewline); + assertTrue(cfg.indentBlankLines); + assertTrue(cfg.indentSchemaLocation); + assertTrue(cfg.quiet); + assertTrue(cfg.sortProperties); + assertTrue(cfg.sortModules); + assertTrue(cfg.sortExecutions); + } + + @Test + void testNumericFieldEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Test minimum value + cfg.nrOfIndentSpace = 0; + assertEquals(0, cfg.nrOfIndentSpace); + + // Test negative value (though probably not valid in practice) + cfg.nrOfIndentSpace = -1; + assertEquals(-1, cfg.nrOfIndentSpace); + + // Test large value + cfg.nrOfIndentSpace = Integer.MAX_VALUE; + assertEquals(Integer.MAX_VALUE, cfg.nrOfIndentSpace); + } +} From 7105f36e83cf1ae3136a214627fd1aed0e15f593 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 10:35:59 +0200 Subject: [PATCH 03/18] Avoid empty body warnings emposed by default activation of expandEmptyElements --- .../com/diffplug/spotless/pom/SortPomCfg.java | 26 ++-- .../gradle/spotless/PomExtension.java | 125 ------------------ 2 files changed, 13 insertions(+), 138 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index db37ae25fd..6ec59ac46a 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -29,7 +29,7 @@ public class SortPomCfg implements Serializable { public boolean expandEmptyElements; - public boolean spaceBeforeCloseEmptyElement = false; + public boolean spaceBeforeCloseEmptyElement; public boolean keepBlankLines = true; @@ -37,29 +37,29 @@ public class SortPomCfg implements Serializable { public int nrOfIndentSpace = 2; - public boolean indentBlankLines = false; + public boolean indentBlankLines; - public boolean indentSchemaLocation = false; + public boolean indentSchemaLocation; - public String indentAttribute = null; + public String indentAttribute; public String predefinedSortOrder = "recommended_2008_06"; - public boolean quiet = false; + public boolean quiet; - public String sortOrderFile = null; + public String sortOrderFile; - public String sortDependencies = null; + public String sortDependencies; - public String sortDependencyManagement = null; + public String sortDependencyManagement; - public String sortDependencyExclusions = null; + public String sortDependencyExclusions; - public String sortPlugins = null; + public String sortPlugins; - public boolean sortProperties = false; + public boolean sortProperties; - public boolean sortModules = false; + public boolean sortModules; - public boolean sortExecutions = false; + public boolean sortExecutions; } diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java index 4fd92c1f02..cb03747a8f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java @@ -41,129 +41,4 @@ protected void setupTask(SpotlessTask task) { super.setupTask(task); } - public SortPomGradleConfig sortPom() { - return new SortPomGradleConfig(); - } - - public SortPomGradleConfig sortPom(String version) { - Objects.requireNonNull(version); - return new SortPomGradleConfig(version); - } - - public class SortPomGradleConfig { - private final SortPomCfg cfg = new SortPomCfg(); - - SortPomGradleConfig() { - addStep(createStep()); - } - - SortPomGradleConfig(String version) { - this(); - cfg.version = Objects.requireNonNull(version); - } - - public SortPomGradleConfig encoding(String encoding) { - cfg.encoding = encoding; - return this; - } - - public SortPomGradleConfig lineSeparator(String lineSeparator) { - cfg.lineSeparator = lineSeparator; - return this; - } - - public SortPomGradleConfig expandEmptyElements(boolean expandEmptyElements) { - cfg.expandEmptyElements = expandEmptyElements; - return this; - } - - public SortPomGradleConfig spaceBeforeCloseEmptyElement(boolean spaceBeforeCloseEmptyElement) { - cfg.spaceBeforeCloseEmptyElement = spaceBeforeCloseEmptyElement; - return this; - } - - public SortPomGradleConfig keepBlankLines(boolean keepBlankLines) { - cfg.keepBlankLines = keepBlankLines; - return this; - } - - public SortPomGradleConfig endWithNewline(boolean endWithNewline) { - cfg.endWithNewline = endWithNewline; - return this; - } - - public SortPomGradleConfig nrOfIndentSpace(int nrOfIndentSpace) { - cfg.nrOfIndentSpace = nrOfIndentSpace; - return this; - } - - public SortPomGradleConfig indentBlankLines(boolean indentBlankLines) { - cfg.indentBlankLines = indentBlankLines; - return this; - } - - public SortPomGradleConfig indentSchemaLocation(boolean indentSchemaLocation) { - cfg.indentSchemaLocation = indentSchemaLocation; - return this; - } - - public SortPomGradleConfig indentAttribute(String indentAttribute) { - cfg.indentAttribute = indentAttribute; - return this; - } - - public SortPomGradleConfig predefinedSortOrder(String predefinedSortOrder) { - cfg.predefinedSortOrder = predefinedSortOrder; - return this; - } - - public SortPomGradleConfig quiet(boolean quiet) { - cfg.quiet = quiet; - return this; - } - - public SortPomGradleConfig sortOrderFile(String sortOrderFile) { - cfg.sortOrderFile = sortOrderFile; - return this; - } - - public SortPomGradleConfig sortDependencies(String sortDependencies) { - cfg.sortDependencies = sortDependencies; - return this; - } - - public SortPomGradleConfig sortDependencyManagement(String sortDependencyManagement) { - cfg.sortDependencyManagement = sortDependencyManagement; - return this; - } - - public SortPomGradleConfig sortDependencyExclusions(String sortDependencyExclusions) { - cfg.sortDependencyExclusions = sortDependencyExclusions; - return this; - } - - public SortPomGradleConfig sortPlugins(String sortPlugins) { - cfg.sortPlugins = sortPlugins; - return this; - } - - public SortPomGradleConfig sortProperties(boolean sortProperties) { - cfg.sortProperties = sortProperties; - return this; - } - - public SortPomGradleConfig sortModules(boolean sortModules) { - cfg.sortModules = sortModules; - return this; - } - - public SortPomGradleConfig sortExecutions(boolean sortExecutions) { - cfg.sortExecutions = sortExecutions; - return this; - } - - private FormatterStep createStep() { - return SortPomStep.create(cfg, provisioner()); - } - } } From 6d6cf720488d6d9e969a684e2ec1f632bca79fe5 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 10:38:51 +0200 Subject: [PATCH 04/18] Avoid empty body warnings imposed by default activation of expandEmptyElements --- .../com/diffplug/spotless/pom/SortPomCfg.java | 30 ++-- .../diffplug/spotless/pom/SortPomCfgTest.java | 162 ++++++++++++++++++ 2 files changed, 177 insertions(+), 15 deletions(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 08a0308178..6ec59ac46a 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +27,9 @@ public class SortPomCfg implements Serializable { public String lineSeparator = System.getProperty("line.separator"); - public boolean expandEmptyElements = true; + public boolean expandEmptyElements; - public boolean spaceBeforeCloseEmptyElement = false; + public boolean spaceBeforeCloseEmptyElement; public boolean keepBlankLines = true; @@ -37,29 +37,29 @@ public class SortPomCfg implements Serializable { public int nrOfIndentSpace = 2; - public boolean indentBlankLines = false; + public boolean indentBlankLines; - public boolean indentSchemaLocation = false; + public boolean indentSchemaLocation; - public String indentAttribute = null; + public String indentAttribute; public String predefinedSortOrder = "recommended_2008_06"; - public boolean quiet = false; + public boolean quiet; - public String sortOrderFile = null; + public String sortOrderFile; - public String sortDependencies = null; + public String sortDependencies; - public String sortDependencyManagement = null; + public String sortDependencyManagement; - public String sortDependencyExclusions = null; + public String sortDependencyExclusions; - public String sortPlugins = null; + public String sortPlugins; - public boolean sortProperties = false; + public boolean sortProperties; - public boolean sortModules = false; + public boolean sortModules; - public boolean sortExecutions = false; + public boolean sortExecutions; } diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java new file mode 100644 index 0000000000..f7decb90f4 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java @@ -0,0 +1,162 @@ +package com.diffplug.spotless.pom; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class SortPomCfgTest { + + @Test + void testDefaultValues() { + SortPomCfg cfg = new SortPomCfg(); + + // Test default values using AssertJ + assertThat(cfg.version).isEqualTo("4.0.0"); + assertThat(cfg.encoding).isEqualTo("UTF-8"); + assertThat(cfg.lineSeparator).isEqualTo(System.getProperty("line.separator")); + assertThat(cfg.expandEmptyElements).isFalse(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isFalse(); + assertThat(cfg.keepBlankLines).isTrue(); + assertThat(cfg.endWithNewline).isTrue(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(2); + assertThat(cfg.indentBlankLines).isFalse(); + assertThat(cfg.indentSchemaLocation).isFalse(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isEqualTo("recommended_2008_06"); + assertThat(cfg.quiet).isFalse(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + assertThat(cfg.sortProperties).isFalse(); + assertThat(cfg.sortModules).isFalse(); + assertThat(cfg.sortExecutions).isFalse(); + } + + @Test + void testFieldSetters() { + SortPomCfg cfg = new SortPomCfg(); + + // Set all fields + cfg.version = "4.1.0"; + cfg.encoding = "ISO-8859-1"; + cfg.lineSeparator = "\n"; + cfg.expandEmptyElements = true; + cfg.spaceBeforeCloseEmptyElement = true; + cfg.keepBlankLines = false; + cfg.endWithNewline = false; + cfg.nrOfIndentSpace = 4; + cfg.indentBlankLines = true; + cfg.indentSchemaLocation = true; + cfg.indentAttribute = "attribute"; + cfg.predefinedSortOrder = "custom"; + cfg.quiet = true; + cfg.sortOrderFile = "sortOrder.xml"; + cfg.sortDependencies = "groupId,artifactId"; + cfg.sortDependencyManagement = "scope,groupId"; + cfg.sortDependencyExclusions = "artifactId"; + cfg.sortPlugins = "groupId"; + cfg.sortProperties = true; + cfg.sortModules = true; + cfg.sortExecutions = true; + + // Verify all set values with AssertJ + assertThat(cfg.version).isEqualTo("4.1.0"); + assertThat(cfg.encoding).isEqualTo("ISO-8859-1"); + assertThat(cfg.lineSeparator).isEqualTo("\n"); + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(4); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.indentAttribute).isEqualTo("attribute"); + assertThat(cfg.predefinedSortOrder).isEqualTo("custom"); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortOrderFile).isEqualTo("sortOrder.xml"); + assertThat(cfg.sortDependencies).isEqualTo("groupId,artifactId"); + assertThat(cfg.sortDependencyManagement).isEqualTo("scope,groupId"); + assertThat(cfg.sortDependencyExclusions).isEqualTo("artifactId"); + assertThat(cfg.sortPlugins).isEqualTo("groupId"); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNullHandling() { + SortPomCfg cfg = new SortPomCfg(); + + // Set nullable fields to null + cfg.version = null; + cfg.encoding = null; + cfg.lineSeparator = null; + cfg.indentAttribute = null; + cfg.predefinedSortOrder = null; + cfg.sortOrderFile = null; + cfg.sortDependencies = null; + cfg.sortDependencyManagement = null; + cfg.sortDependencyExclusions = null; + cfg.sortPlugins = null; + + // Verify null values with AssertJ + assertThat(cfg.version).isNull(); + assertThat(cfg.encoding).isNull(); + assertThat(cfg.lineSeparator).isNull(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isNull(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + } + + @Test + void testBooleanFieldsEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Toggle all boolean fields + cfg.expandEmptyElements = !cfg.expandEmptyElements; + cfg.spaceBeforeCloseEmptyElement = !cfg.spaceBeforeCloseEmptyElement; + cfg.keepBlankLines = !cfg.keepBlankLines; + cfg.endWithNewline = !cfg.endWithNewline; + cfg.indentBlankLines = !cfg.indentBlankLines; + cfg.indentSchemaLocation = !cfg.indentSchemaLocation; + cfg.quiet = !cfg.quiet; + cfg.sortProperties = !cfg.sortProperties; + cfg.sortModules = !cfg.sortModules; + cfg.sortExecutions = !cfg.sortExecutions; + + // Verify all boolean fields are toggled + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNumericFieldEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Test minimum value + cfg.nrOfIndentSpace = 0; + assertThat(cfg.nrOfIndentSpace).isZero(); + + // Test negative value + cfg.nrOfIndentSpace = -1; + assertThat(cfg.nrOfIndentSpace).isNegative(); + + // Test large value + cfg.nrOfIndentSpace = Integer.MAX_VALUE; + assertThat(cfg.nrOfIndentSpace).isEqualTo(Integer.MAX_VALUE); + } +} From 6eefa33885f0675ab256da9e5f88757ad19df78f Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 10:52:07 +0200 Subject: [PATCH 05/18] remove pom --- .../java/com/diffplug/gradle/spotless/PomExtension.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java index cb03747a8f..bafbe36071 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java @@ -15,14 +15,8 @@ */ package com.diffplug.gradle.spotless; -import java.util.Objects; - import javax.inject.Inject; -import com.diffplug.spotless.FormatterStep; -import com.diffplug.spotless.pom.SortPomCfg; -import com.diffplug.spotless.pom.SortPomStep; - public class PomExtension extends FormatExtension { private static final String POM_FILE = "pom.xml"; From c99dfdcd4d1e4fdf31a1a647957777c9a35133d5 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 10:38:51 +0200 Subject: [PATCH 06/18] Avoid empty body warnings imposed by default activation of expandEmptyElements --- .../com/diffplug/spotless/pom/SortPomCfg.java | 30 +-- .../diffplug/spotless/pom/SortPomCfgTest.java | 177 ++++++++++++++++++ 2 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 08a0308178..6ec59ac46a 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2024 DiffPlug + * Copyright 2021-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,9 +27,9 @@ public class SortPomCfg implements Serializable { public String lineSeparator = System.getProperty("line.separator"); - public boolean expandEmptyElements = true; + public boolean expandEmptyElements; - public boolean spaceBeforeCloseEmptyElement = false; + public boolean spaceBeforeCloseEmptyElement; public boolean keepBlankLines = true; @@ -37,29 +37,29 @@ public class SortPomCfg implements Serializable { public int nrOfIndentSpace = 2; - public boolean indentBlankLines = false; + public boolean indentBlankLines; - public boolean indentSchemaLocation = false; + public boolean indentSchemaLocation; - public String indentAttribute = null; + public String indentAttribute; public String predefinedSortOrder = "recommended_2008_06"; - public boolean quiet = false; + public boolean quiet; - public String sortOrderFile = null; + public String sortOrderFile; - public String sortDependencies = null; + public String sortDependencies; - public String sortDependencyManagement = null; + public String sortDependencyManagement; - public String sortDependencyExclusions = null; + public String sortDependencyExclusions; - public String sortPlugins = null; + public String sortPlugins; - public boolean sortProperties = false; + public boolean sortProperties; - public boolean sortModules = false; + public boolean sortModules; - public boolean sortExecutions = false; + public boolean sortExecutions; } diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java new file mode 100644 index 0000000000..b0a336f189 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java @@ -0,0 +1,177 @@ +/* + * Copyright 2025 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.pom; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class SortPomCfgTest { + + @Test + void testDefaultValues() { + SortPomCfg cfg = new SortPomCfg(); + + // Test default values using AssertJ + assertThat(cfg.version).isEqualTo("4.0.0"); + assertThat(cfg.encoding).isEqualTo("UTF-8"); + assertThat(cfg.lineSeparator).isEqualTo(System.getProperty("line.separator")); + assertThat(cfg.expandEmptyElements).isFalse(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isFalse(); + assertThat(cfg.keepBlankLines).isTrue(); + assertThat(cfg.endWithNewline).isTrue(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(2); + assertThat(cfg.indentBlankLines).isFalse(); + assertThat(cfg.indentSchemaLocation).isFalse(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isEqualTo("recommended_2008_06"); + assertThat(cfg.quiet).isFalse(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + assertThat(cfg.sortProperties).isFalse(); + assertThat(cfg.sortModules).isFalse(); + assertThat(cfg.sortExecutions).isFalse(); + } + + @Test + void testFieldSetters() { + SortPomCfg cfg = new SortPomCfg(); + + // Set all fields + cfg.version = "4.1.0"; + cfg.encoding = "ISO-8859-1"; + cfg.lineSeparator = "\n"; + cfg.expandEmptyElements = true; + cfg.spaceBeforeCloseEmptyElement = true; + cfg.keepBlankLines = false; + cfg.endWithNewline = false; + cfg.nrOfIndentSpace = 4; + cfg.indentBlankLines = true; + cfg.indentSchemaLocation = true; + cfg.indentAttribute = "attribute"; + cfg.predefinedSortOrder = "custom"; + cfg.quiet = true; + cfg.sortOrderFile = "sortOrder.xml"; + cfg.sortDependencies = "groupId,artifactId"; + cfg.sortDependencyManagement = "scope,groupId"; + cfg.sortDependencyExclusions = "artifactId"; + cfg.sortPlugins = "groupId"; + cfg.sortProperties = true; + cfg.sortModules = true; + cfg.sortExecutions = true; + + // Verify all set values with AssertJ + assertThat(cfg.version).isEqualTo("4.1.0"); + assertThat(cfg.encoding).isEqualTo("ISO-8859-1"); + assertThat(cfg.lineSeparator).isEqualTo("\n"); + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.nrOfIndentSpace).isEqualTo(4); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.indentAttribute).isEqualTo("attribute"); + assertThat(cfg.predefinedSortOrder).isEqualTo("custom"); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortOrderFile).isEqualTo("sortOrder.xml"); + assertThat(cfg.sortDependencies).isEqualTo("groupId,artifactId"); + assertThat(cfg.sortDependencyManagement).isEqualTo("scope,groupId"); + assertThat(cfg.sortDependencyExclusions).isEqualTo("artifactId"); + assertThat(cfg.sortPlugins).isEqualTo("groupId"); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNullHandling() { + SortPomCfg cfg = new SortPomCfg(); + + // Set nullable fields to null + cfg.version = null; + cfg.encoding = null; + cfg.lineSeparator = null; + cfg.indentAttribute = null; + cfg.predefinedSortOrder = null; + cfg.sortOrderFile = null; + cfg.sortDependencies = null; + cfg.sortDependencyManagement = null; + cfg.sortDependencyExclusions = null; + cfg.sortPlugins = null; + + // Verify null values with AssertJ + assertThat(cfg.version).isNull(); + assertThat(cfg.encoding).isNull(); + assertThat(cfg.lineSeparator).isNull(); + assertThat(cfg.indentAttribute).isNull(); + assertThat(cfg.predefinedSortOrder).isNull(); + assertThat(cfg.sortOrderFile).isNull(); + assertThat(cfg.sortDependencies).isNull(); + assertThat(cfg.sortDependencyManagement).isNull(); + assertThat(cfg.sortDependencyExclusions).isNull(); + assertThat(cfg.sortPlugins).isNull(); + } + + @Test + void testBooleanFieldsEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Toggle all boolean fields + cfg.expandEmptyElements = !cfg.expandEmptyElements; + cfg.spaceBeforeCloseEmptyElement = !cfg.spaceBeforeCloseEmptyElement; + cfg.keepBlankLines = !cfg.keepBlankLines; + cfg.endWithNewline = !cfg.endWithNewline; + cfg.indentBlankLines = !cfg.indentBlankLines; + cfg.indentSchemaLocation = !cfg.indentSchemaLocation; + cfg.quiet = !cfg.quiet; + cfg.sortProperties = !cfg.sortProperties; + cfg.sortModules = !cfg.sortModules; + cfg.sortExecutions = !cfg.sortExecutions; + + // Verify all boolean fields are toggled + assertThat(cfg.expandEmptyElements).isTrue(); + assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); + assertThat(cfg.keepBlankLines).isFalse(); + assertThat(cfg.endWithNewline).isFalse(); + assertThat(cfg.indentBlankLines).isTrue(); + assertThat(cfg.indentSchemaLocation).isTrue(); + assertThat(cfg.quiet).isTrue(); + assertThat(cfg.sortProperties).isTrue(); + assertThat(cfg.sortModules).isTrue(); + assertThat(cfg.sortExecutions).isTrue(); + } + + @Test + void testNumericFieldEdgeCases() { + SortPomCfg cfg = new SortPomCfg(); + + // Test minimum value + cfg.nrOfIndentSpace = 0; + assertThat(cfg.nrOfIndentSpace).isZero(); + + // Test negative value + cfg.nrOfIndentSpace = -1; + assertThat(cfg.nrOfIndentSpace).isNegative(); + + // Test large value + cfg.nrOfIndentSpace = Integer.MAX_VALUE; + assertThat(cfg.nrOfIndentSpace).isEqualTo(Integer.MAX_VALUE); + } +} From 3dd75bd60ce8eacdd93140d8381103bc7fa42403 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 11:14:10 +0200 Subject: [PATCH 07/18] Avoid empty body warnings imposed by default activation of expandEmptyElements --- .../main/java/com/diffplug/gradle/spotless/PomExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java index bafbe36071..d81c245e9f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 DiffPlug + * Copyright 2024-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From bcbe6e5eabe4a3c41ef13e9eca13118db2f6c5f2 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 11:14:10 +0200 Subject: [PATCH 08/18] remove obsoletes found in SortPomCfg and PomExtension --- .../main/java/com/diffplug/gradle/spotless/PomExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java index bafbe36071..d81c245e9f 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 DiffPlug + * Copyright 2024-2025 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 961ebe7e9220c971d0ff7a2fd9948496fc9f083c Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 11:40:11 +0200 Subject: [PATCH 09/18] remove obsoletes found in SortPomCfg and PomExtension --- .../extra/glue/groovy/GrEclipseFormatterStepImpl.java | 4 +++- lib/src/main/java/com/diffplug/spotless/Jvm.java | 5 ++++- lib/src/main/java/com/diffplug/spotless/LineEnding.java | 4 +++- .../com/diffplug/spotless/groovy/RemoveSemicolonsStep.java | 4 +++- lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java | 4 +++- .../test/java/com/diffplug/spotless/pom/SortPomCfgTest.java | 3 ++- 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java b/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java index 163816c1a4..fd3aa0fe3c 100644 --- a/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java +++ b/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java @@ -48,6 +48,8 @@ import dev.equo.solstice.Solstice; import dev.equo.solstice.p2.CacheLocations; +import static java.lang.System.lineSeparator; + /** Spotless-Formatter step which calls out to the Groovy-Eclipse formatter. */ public class GrEclipseFormatterStepImpl { static { @@ -143,7 +145,7 @@ public String toString() { } for (Throwable error : errors) { error.printStackTrace(); - string.append(System.lineSeparator()); + string.append(lineSeparator()); string.append(error.getMessage()); } diff --git a/lib/src/main/java/com/diffplug/spotless/Jvm.java b/lib/src/main/java/com/diffplug/spotless/Jvm.java index 3e8339644a..27204214e6 100644 --- a/lib/src/main/java/com/diffplug/spotless/Jvm.java +++ b/lib/src/main/java/com/diffplug/spotless/Jvm.java @@ -31,6 +31,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import static java.lang.System.lineSeparator; +import static java.util.stream.Collectors.joining; + /** Java virtual machine helper */ public final class Jvm { private static final int VERSION; @@ -255,7 +258,7 @@ private String buildUpgradeFormatterMessage(V fmtVersion) { public String toString() { return String.format("%s alternatives:%n", fmtName) + jvm2fmtMaxVersion.entrySet().stream().map( - e -> String.format("- Version %s requires JVM %d+", e.getValue(), e.getKey())).collect(Collectors.joining(System.lineSeparator())); + e -> String.format("- Version %s requires JVM %d+", e.getValue(), e.getKey())).collect(joining(lineSeparator())); } @SuppressFBWarnings("SE_COMPARATOR_SHOULD_BE_SERIALIZABLE") diff --git a/lib/src/main/java/com/diffplug/spotless/LineEnding.java b/lib/src/main/java/com/diffplug/spotless/LineEnding.java index 5b44b81889..44d33e2441 100644 --- a/lib/src/main/java/com/diffplug/spotless/LineEnding.java +++ b/lib/src/main/java/com/diffplug/spotless/LineEnding.java @@ -25,6 +25,8 @@ import java.util.Objects; import java.util.function.Supplier; +import static java.lang.System.lineSeparator; + /** * Represents the line endings which should be written by the tool. */ @@ -151,7 +153,7 @@ static String getEndingFor(Reader reader) throws IOException { private static final Policy UNIX_POLICY = new ConstantLineEndingPolicy(UNIX.str()); private static final Policy MAC_CLASSIC_POLICY = new ConstantLineEndingPolicy(MAC_CLASSIC.str()); private static final Policy PRESERVE_POLICY = new PreserveLineEndingPolicy(); - private static final String _platformNative = System.getProperty("line.separator"); + private static final String _platformNative = lineSeparator(); private static final Policy _platformNativePolicy = new ConstantLineEndingPolicy(_platformNative); private static final boolean nativeIsWin = _platformNative.equals(WINDOWS.str()); diff --git a/lib/src/main/java/com/diffplug/spotless/groovy/RemoveSemicolonsStep.java b/lib/src/main/java/com/diffplug/spotless/groovy/RemoveSemicolonsStep.java index 6dc3185ef6..0fef566f25 100644 --- a/lib/src/main/java/com/diffplug/spotless/groovy/RemoveSemicolonsStep.java +++ b/lib/src/main/java/com/diffplug/spotless/groovy/RemoveSemicolonsStep.java @@ -22,6 +22,8 @@ import com.diffplug.spotless.FormatterFunc; import com.diffplug.spotless.FormatterStep; +import static java.lang.System.lineSeparator; + /** * Removes all semicolons from the end of lines. * @@ -51,7 +53,7 @@ FormatterFunc toFormatter() { String line; while ((line = reader.readLine()) != null) { result.append(removeSemicolon(line)); - result.append(System.lineSeparator()); + result.append(lineSeparator()); } return result.toString(); } diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 6ec59ac46a..6f77e9c349 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -17,6 +17,8 @@ import java.io.Serializable; +import static java.lang.System.lineSeparator; + // Class and members must be public, otherwise we get failed to access class com.diffplug.spotless.pom.SortPomInternalState from class com.diffplug.spotless.pom.SortPomFormatterFunc (com.diffplug.spotless.pom.SortPomInternalState is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @682bd3c4; com.diffplug.spotless.pom.SortPomFormatterFunc is in unnamed module of loader com.diffplug.spotless.pom.DelegatingClassLoader @573284a5) public class SortPomCfg implements Serializable { private static final long serialVersionUID = 1L; @@ -25,7 +27,7 @@ public class SortPomCfg implements Serializable { public String encoding = "UTF-8"; - public String lineSeparator = System.getProperty("line.separator"); + public String lineSeparator = lineSeparator(); public boolean expandEmptyElements; diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java index b0a336f189..4ce97d0355 100644 --- a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java +++ b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java @@ -15,6 +15,7 @@ */ package com.diffplug.spotless.pom; +import static java.lang.System.lineSeparator; import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; @@ -28,7 +29,7 @@ void testDefaultValues() { // Test default values using AssertJ assertThat(cfg.version).isEqualTo("4.0.0"); assertThat(cfg.encoding).isEqualTo("UTF-8"); - assertThat(cfg.lineSeparator).isEqualTo(System.getProperty("line.separator")); + assertThat(cfg.lineSeparator).isEqualTo(lineSeparator()); assertThat(cfg.expandEmptyElements).isFalse(); assertThat(cfg.spaceBeforeCloseEmptyElement).isFalse(); assertThat(cfg.keepBlankLines).isTrue(); From 2ca859acc9b99cc78c1a8c777d73dd01eb547434 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 11:49:10 +0200 Subject: [PATCH 10/18] remove obsoletes found in SortPomCfg and PomExtension --- .../sql/dbeaver/SQLTokenizedFormatter.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index 01f0fd759e..55fa97fb20 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -22,6 +22,8 @@ import com.diffplug.spotless.annotations.Internal; +import static java.lang.System.lineSeparator; + /** * **Warning:** Use this class at your own risk. It is an implementation detail and is not * guaranteed to exist in future versions. @@ -67,7 +69,7 @@ public String format(final String argSql) { } if (isSqlEndsWithNewLine) { - after.append(getDefaultLineSeparator()); + after.append(lineSeparator()); } return after.toString(); @@ -388,19 +390,12 @@ private boolean isFunction(String name) { return sqlDialect.getKeywordType(name) == DBPKeywordType.FUNCTION; } - private static String getDefaultLineSeparator() { - return System.getProperty("line.separator", "\n"); - } - private int insertReturnAndIndent(final List argList, final int argIndex, final int argIndent) { if (functionBracket.contains(Boolean.TRUE)) return 0; try { - final String defaultLineSeparator = getDefaultLineSeparator(); - StringBuilder s = new StringBuilder(defaultLineSeparator); - for (int index = 0; index < argIndent; index++) { - s.append(formatterCfg.getIndentString()); - } + StringBuilder s = new StringBuilder(lineSeparator()); + s.append(String.valueOf(formatterCfg.getIndentString()).repeat(Math.max(0, argIndent))); if (argIndex > 0) { final FormatterToken token = argList.get(argIndex); final FormatterToken prevToken = argList.get(argIndex - 1); @@ -409,10 +404,7 @@ private int insertReturnAndIndent(final List argList, final int prevToken.getType() != TokenType.END) { s.setCharAt(0, ' '); s.setLength(1); - - final String comment = token.getString(); - final String withoutTrailingWhitespace = comment.replaceFirst("\\s*$", ""); - token.setString(withoutTrailingWhitespace); + token.setString(token.getString().replaceFirst("\\s*$", "")); } } From 8e73be53881e96099672158e74639acb40fe44f2 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:08:59 +0200 Subject: [PATCH 11/18] fix lineSeparator --- .../groovy/GrEclipseFormatterStepImpl.java | 4 +- .../main/java/com/diffplug/spotless/Jvm.java | 5 +- .../com/diffplug/spotless/LineEnding.java | 4 +- .../com/diffplug/spotless/pom/SortPomCfg.java | 34 ++-- .../sql/dbeaver/SQLTokenizedFormatter.java | 20 +- .../diffplug/spotless/pom/SortPomCfgTest.java | 178 ------------------ .../gradle/spotless/PomExtension.java | 133 ++++++++++++- 7 files changed, 165 insertions(+), 213 deletions(-) delete mode 100644 lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java diff --git a/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java b/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java index fd3aa0fe3c..163816c1a4 100644 --- a/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java +++ b/lib-extra/src/groovy/java/com/diffplug/spotless/extra/glue/groovy/GrEclipseFormatterStepImpl.java @@ -48,8 +48,6 @@ import dev.equo.solstice.Solstice; import dev.equo.solstice.p2.CacheLocations; -import static java.lang.System.lineSeparator; - /** Spotless-Formatter step which calls out to the Groovy-Eclipse formatter. */ public class GrEclipseFormatterStepImpl { static { @@ -145,7 +143,7 @@ public String toString() { } for (Throwable error : errors) { error.printStackTrace(); - string.append(lineSeparator()); + string.append(System.lineSeparator()); string.append(error.getMessage()); } diff --git a/lib/src/main/java/com/diffplug/spotless/Jvm.java b/lib/src/main/java/com/diffplug/spotless/Jvm.java index 27204214e6..3e8339644a 100644 --- a/lib/src/main/java/com/diffplug/spotless/Jvm.java +++ b/lib/src/main/java/com/diffplug/spotless/Jvm.java @@ -31,9 +31,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import static java.lang.System.lineSeparator; -import static java.util.stream.Collectors.joining; - /** Java virtual machine helper */ public final class Jvm { private static final int VERSION; @@ -258,7 +255,7 @@ private String buildUpgradeFormatterMessage(V fmtVersion) { public String toString() { return String.format("%s alternatives:%n", fmtName) + jvm2fmtMaxVersion.entrySet().stream().map( - e -> String.format("- Version %s requires JVM %d+", e.getValue(), e.getKey())).collect(joining(lineSeparator())); + e -> String.format("- Version %s requires JVM %d+", e.getValue(), e.getKey())).collect(Collectors.joining(System.lineSeparator())); } @SuppressFBWarnings("SE_COMPARATOR_SHOULD_BE_SERIALIZABLE") diff --git a/lib/src/main/java/com/diffplug/spotless/LineEnding.java b/lib/src/main/java/com/diffplug/spotless/LineEnding.java index 44d33e2441..5b44b81889 100644 --- a/lib/src/main/java/com/diffplug/spotless/LineEnding.java +++ b/lib/src/main/java/com/diffplug/spotless/LineEnding.java @@ -25,8 +25,6 @@ import java.util.Objects; import java.util.function.Supplier; -import static java.lang.System.lineSeparator; - /** * Represents the line endings which should be written by the tool. */ @@ -153,7 +151,7 @@ static String getEndingFor(Reader reader) throws IOException { private static final Policy UNIX_POLICY = new ConstantLineEndingPolicy(UNIX.str()); private static final Policy MAC_CLASSIC_POLICY = new ConstantLineEndingPolicy(MAC_CLASSIC.str()); private static final Policy PRESERVE_POLICY = new PreserveLineEndingPolicy(); - private static final String _platformNative = lineSeparator(); + private static final String _platformNative = System.getProperty("line.separator"); private static final Policy _platformNativePolicy = new ConstantLineEndingPolicy(_platformNative); private static final boolean nativeIsWin = _platformNative.equals(WINDOWS.str()); diff --git a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java index 6f77e9c349..08a0308178 100644 --- a/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java +++ b/lib/src/main/java/com/diffplug/spotless/pom/SortPomCfg.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2025 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. @@ -17,8 +17,6 @@ import java.io.Serializable; -import static java.lang.System.lineSeparator; - // Class and members must be public, otherwise we get failed to access class com.diffplug.spotless.pom.SortPomInternalState from class com.diffplug.spotless.pom.SortPomFormatterFunc (com.diffplug.spotless.pom.SortPomInternalState is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @682bd3c4; com.diffplug.spotless.pom.SortPomFormatterFunc is in unnamed module of loader com.diffplug.spotless.pom.DelegatingClassLoader @573284a5) public class SortPomCfg implements Serializable { private static final long serialVersionUID = 1L; @@ -27,11 +25,11 @@ public class SortPomCfg implements Serializable { public String encoding = "UTF-8"; - public String lineSeparator = lineSeparator(); + public String lineSeparator = System.getProperty("line.separator"); - public boolean expandEmptyElements; + public boolean expandEmptyElements = true; - public boolean spaceBeforeCloseEmptyElement; + public boolean spaceBeforeCloseEmptyElement = false; public boolean keepBlankLines = true; @@ -39,29 +37,29 @@ public class SortPomCfg implements Serializable { public int nrOfIndentSpace = 2; - public boolean indentBlankLines; + public boolean indentBlankLines = false; - public boolean indentSchemaLocation; + public boolean indentSchemaLocation = false; - public String indentAttribute; + public String indentAttribute = null; public String predefinedSortOrder = "recommended_2008_06"; - public boolean quiet; + public boolean quiet = false; - public String sortOrderFile; + public String sortOrderFile = null; - public String sortDependencies; + public String sortDependencies = null; - public String sortDependencyManagement; + public String sortDependencyManagement = null; - public String sortDependencyExclusions; + public String sortDependencyExclusions = null; - public String sortPlugins; + public String sortPlugins = null; - public boolean sortProperties; + public boolean sortProperties = false; - public boolean sortModules; + public boolean sortModules = false; - public boolean sortExecutions; + public boolean sortExecutions = false; } diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index 55fa97fb20..01f0fd759e 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -22,8 +22,6 @@ import com.diffplug.spotless.annotations.Internal; -import static java.lang.System.lineSeparator; - /** * **Warning:** Use this class at your own risk. It is an implementation detail and is not * guaranteed to exist in future versions. @@ -69,7 +67,7 @@ public String format(final String argSql) { } if (isSqlEndsWithNewLine) { - after.append(lineSeparator()); + after.append(getDefaultLineSeparator()); } return after.toString(); @@ -390,12 +388,19 @@ private boolean isFunction(String name) { return sqlDialect.getKeywordType(name) == DBPKeywordType.FUNCTION; } + private static String getDefaultLineSeparator() { + return System.getProperty("line.separator", "\n"); + } + private int insertReturnAndIndent(final List argList, final int argIndex, final int argIndent) { if (functionBracket.contains(Boolean.TRUE)) return 0; try { - StringBuilder s = new StringBuilder(lineSeparator()); - s.append(String.valueOf(formatterCfg.getIndentString()).repeat(Math.max(0, argIndent))); + final String defaultLineSeparator = getDefaultLineSeparator(); + StringBuilder s = new StringBuilder(defaultLineSeparator); + for (int index = 0; index < argIndent; index++) { + s.append(formatterCfg.getIndentString()); + } if (argIndex > 0) { final FormatterToken token = argList.get(argIndex); final FormatterToken prevToken = argList.get(argIndex - 1); @@ -404,7 +409,10 @@ private int insertReturnAndIndent(final List argList, final int prevToken.getType() != TokenType.END) { s.setCharAt(0, ' '); s.setLength(1); - token.setString(token.getString().replaceFirst("\\s*$", "")); + + final String comment = token.getString(); + final String withoutTrailingWhitespace = comment.replaceFirst("\\s*$", ""); + token.setString(withoutTrailingWhitespace); } } diff --git a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java b/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java deleted file mode 100644 index 4ce97d0355..0000000000 --- a/lib/src/test/java/com/diffplug/spotless/pom/SortPomCfgTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2025 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.pom; - -import static java.lang.System.lineSeparator; -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -class SortPomCfgTest { - - @Test - void testDefaultValues() { - SortPomCfg cfg = new SortPomCfg(); - - // Test default values using AssertJ - assertThat(cfg.version).isEqualTo("4.0.0"); - assertThat(cfg.encoding).isEqualTo("UTF-8"); - assertThat(cfg.lineSeparator).isEqualTo(lineSeparator()); - assertThat(cfg.expandEmptyElements).isFalse(); - assertThat(cfg.spaceBeforeCloseEmptyElement).isFalse(); - assertThat(cfg.keepBlankLines).isTrue(); - assertThat(cfg.endWithNewline).isTrue(); - assertThat(cfg.nrOfIndentSpace).isEqualTo(2); - assertThat(cfg.indentBlankLines).isFalse(); - assertThat(cfg.indentSchemaLocation).isFalse(); - assertThat(cfg.indentAttribute).isNull(); - assertThat(cfg.predefinedSortOrder).isEqualTo("recommended_2008_06"); - assertThat(cfg.quiet).isFalse(); - assertThat(cfg.sortOrderFile).isNull(); - assertThat(cfg.sortDependencies).isNull(); - assertThat(cfg.sortDependencyManagement).isNull(); - assertThat(cfg.sortDependencyExclusions).isNull(); - assertThat(cfg.sortPlugins).isNull(); - assertThat(cfg.sortProperties).isFalse(); - assertThat(cfg.sortModules).isFalse(); - assertThat(cfg.sortExecutions).isFalse(); - } - - @Test - void testFieldSetters() { - SortPomCfg cfg = new SortPomCfg(); - - // Set all fields - cfg.version = "4.1.0"; - cfg.encoding = "ISO-8859-1"; - cfg.lineSeparator = "\n"; - cfg.expandEmptyElements = true; - cfg.spaceBeforeCloseEmptyElement = true; - cfg.keepBlankLines = false; - cfg.endWithNewline = false; - cfg.nrOfIndentSpace = 4; - cfg.indentBlankLines = true; - cfg.indentSchemaLocation = true; - cfg.indentAttribute = "attribute"; - cfg.predefinedSortOrder = "custom"; - cfg.quiet = true; - cfg.sortOrderFile = "sortOrder.xml"; - cfg.sortDependencies = "groupId,artifactId"; - cfg.sortDependencyManagement = "scope,groupId"; - cfg.sortDependencyExclusions = "artifactId"; - cfg.sortPlugins = "groupId"; - cfg.sortProperties = true; - cfg.sortModules = true; - cfg.sortExecutions = true; - - // Verify all set values with AssertJ - assertThat(cfg.version).isEqualTo("4.1.0"); - assertThat(cfg.encoding).isEqualTo("ISO-8859-1"); - assertThat(cfg.lineSeparator).isEqualTo("\n"); - assertThat(cfg.expandEmptyElements).isTrue(); - assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); - assertThat(cfg.keepBlankLines).isFalse(); - assertThat(cfg.endWithNewline).isFalse(); - assertThat(cfg.nrOfIndentSpace).isEqualTo(4); - assertThat(cfg.indentBlankLines).isTrue(); - assertThat(cfg.indentSchemaLocation).isTrue(); - assertThat(cfg.indentAttribute).isEqualTo("attribute"); - assertThat(cfg.predefinedSortOrder).isEqualTo("custom"); - assertThat(cfg.quiet).isTrue(); - assertThat(cfg.sortOrderFile).isEqualTo("sortOrder.xml"); - assertThat(cfg.sortDependencies).isEqualTo("groupId,artifactId"); - assertThat(cfg.sortDependencyManagement).isEqualTo("scope,groupId"); - assertThat(cfg.sortDependencyExclusions).isEqualTo("artifactId"); - assertThat(cfg.sortPlugins).isEqualTo("groupId"); - assertThat(cfg.sortProperties).isTrue(); - assertThat(cfg.sortModules).isTrue(); - assertThat(cfg.sortExecutions).isTrue(); - } - - @Test - void testNullHandling() { - SortPomCfg cfg = new SortPomCfg(); - - // Set nullable fields to null - cfg.version = null; - cfg.encoding = null; - cfg.lineSeparator = null; - cfg.indentAttribute = null; - cfg.predefinedSortOrder = null; - cfg.sortOrderFile = null; - cfg.sortDependencies = null; - cfg.sortDependencyManagement = null; - cfg.sortDependencyExclusions = null; - cfg.sortPlugins = null; - - // Verify null values with AssertJ - assertThat(cfg.version).isNull(); - assertThat(cfg.encoding).isNull(); - assertThat(cfg.lineSeparator).isNull(); - assertThat(cfg.indentAttribute).isNull(); - assertThat(cfg.predefinedSortOrder).isNull(); - assertThat(cfg.sortOrderFile).isNull(); - assertThat(cfg.sortDependencies).isNull(); - assertThat(cfg.sortDependencyManagement).isNull(); - assertThat(cfg.sortDependencyExclusions).isNull(); - assertThat(cfg.sortPlugins).isNull(); - } - - @Test - void testBooleanFieldsEdgeCases() { - SortPomCfg cfg = new SortPomCfg(); - - // Toggle all boolean fields - cfg.expandEmptyElements = !cfg.expandEmptyElements; - cfg.spaceBeforeCloseEmptyElement = !cfg.spaceBeforeCloseEmptyElement; - cfg.keepBlankLines = !cfg.keepBlankLines; - cfg.endWithNewline = !cfg.endWithNewline; - cfg.indentBlankLines = !cfg.indentBlankLines; - cfg.indentSchemaLocation = !cfg.indentSchemaLocation; - cfg.quiet = !cfg.quiet; - cfg.sortProperties = !cfg.sortProperties; - cfg.sortModules = !cfg.sortModules; - cfg.sortExecutions = !cfg.sortExecutions; - - // Verify all boolean fields are toggled - assertThat(cfg.expandEmptyElements).isTrue(); - assertThat(cfg.spaceBeforeCloseEmptyElement).isTrue(); - assertThat(cfg.keepBlankLines).isFalse(); - assertThat(cfg.endWithNewline).isFalse(); - assertThat(cfg.indentBlankLines).isTrue(); - assertThat(cfg.indentSchemaLocation).isTrue(); - assertThat(cfg.quiet).isTrue(); - assertThat(cfg.sortProperties).isTrue(); - assertThat(cfg.sortModules).isTrue(); - assertThat(cfg.sortExecutions).isTrue(); - } - - @Test - void testNumericFieldEdgeCases() { - SortPomCfg cfg = new SortPomCfg(); - - // Test minimum value - cfg.nrOfIndentSpace = 0; - assertThat(cfg.nrOfIndentSpace).isZero(); - - // Test negative value - cfg.nrOfIndentSpace = -1; - assertThat(cfg.nrOfIndentSpace).isNegative(); - - // Test large value - cfg.nrOfIndentSpace = Integer.MAX_VALUE; - assertThat(cfg.nrOfIndentSpace).isEqualTo(Integer.MAX_VALUE); - } -} diff --git a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java index d81c245e9f..4fd92c1f02 100644 --- a/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java +++ b/plugin-gradle/src/main/java/com/diffplug/gradle/spotless/PomExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 DiffPlug + * Copyright 2024 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,14 @@ */ package com.diffplug.gradle.spotless; +import java.util.Objects; + import javax.inject.Inject; +import com.diffplug.spotless.FormatterStep; +import com.diffplug.spotless.pom.SortPomCfg; +import com.diffplug.spotless.pom.SortPomStep; + public class PomExtension extends FormatExtension { private static final String POM_FILE = "pom.xml"; @@ -35,4 +41,129 @@ protected void setupTask(SpotlessTask task) { super.setupTask(task); } + public SortPomGradleConfig sortPom() { + return new SortPomGradleConfig(); + } + + public SortPomGradleConfig sortPom(String version) { + Objects.requireNonNull(version); + return new SortPomGradleConfig(version); + } + + public class SortPomGradleConfig { + private final SortPomCfg cfg = new SortPomCfg(); + + SortPomGradleConfig() { + addStep(createStep()); + } + + SortPomGradleConfig(String version) { + this(); + cfg.version = Objects.requireNonNull(version); + } + + public SortPomGradleConfig encoding(String encoding) { + cfg.encoding = encoding; + return this; + } + + public SortPomGradleConfig lineSeparator(String lineSeparator) { + cfg.lineSeparator = lineSeparator; + return this; + } + + public SortPomGradleConfig expandEmptyElements(boolean expandEmptyElements) { + cfg.expandEmptyElements = expandEmptyElements; + return this; + } + + public SortPomGradleConfig spaceBeforeCloseEmptyElement(boolean spaceBeforeCloseEmptyElement) { + cfg.spaceBeforeCloseEmptyElement = spaceBeforeCloseEmptyElement; + return this; + } + + public SortPomGradleConfig keepBlankLines(boolean keepBlankLines) { + cfg.keepBlankLines = keepBlankLines; + return this; + } + + public SortPomGradleConfig endWithNewline(boolean endWithNewline) { + cfg.endWithNewline = endWithNewline; + return this; + } + + public SortPomGradleConfig nrOfIndentSpace(int nrOfIndentSpace) { + cfg.nrOfIndentSpace = nrOfIndentSpace; + return this; + } + + public SortPomGradleConfig indentBlankLines(boolean indentBlankLines) { + cfg.indentBlankLines = indentBlankLines; + return this; + } + + public SortPomGradleConfig indentSchemaLocation(boolean indentSchemaLocation) { + cfg.indentSchemaLocation = indentSchemaLocation; + return this; + } + + public SortPomGradleConfig indentAttribute(String indentAttribute) { + cfg.indentAttribute = indentAttribute; + return this; + } + + public SortPomGradleConfig predefinedSortOrder(String predefinedSortOrder) { + cfg.predefinedSortOrder = predefinedSortOrder; + return this; + } + + public SortPomGradleConfig quiet(boolean quiet) { + cfg.quiet = quiet; + return this; + } + + public SortPomGradleConfig sortOrderFile(String sortOrderFile) { + cfg.sortOrderFile = sortOrderFile; + return this; + } + + public SortPomGradleConfig sortDependencies(String sortDependencies) { + cfg.sortDependencies = sortDependencies; + return this; + } + + public SortPomGradleConfig sortDependencyManagement(String sortDependencyManagement) { + cfg.sortDependencyManagement = sortDependencyManagement; + return this; + } + + public SortPomGradleConfig sortDependencyExclusions(String sortDependencyExclusions) { + cfg.sortDependencyExclusions = sortDependencyExclusions; + return this; + } + + public SortPomGradleConfig sortPlugins(String sortPlugins) { + cfg.sortPlugins = sortPlugins; + return this; + } + + public SortPomGradleConfig sortProperties(boolean sortProperties) { + cfg.sortProperties = sortProperties; + return this; + } + + public SortPomGradleConfig sortModules(boolean sortModules) { + cfg.sortModules = sortModules; + return this; + } + + public SortPomGradleConfig sortExecutions(boolean sortExecutions) { + cfg.sortExecutions = sortExecutions; + return this; + } + + private FormatterStep createStep() { + return SortPomStep.create(cfg, provisioner()); + } + } } From 584bdbc207e4f55d6835e5b601dd32f22862f841 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:12:02 +0200 Subject: [PATCH 12/18] fix Reports loops that can be replaced with a single String.repeat() method (available since Java 11). --- .../java/com/diffplug/spotless/generic/IndentStep.java | 8 ++------ .../sql/dbeaver/DBeaverSQLFormatterConfiguration.java | 4 +--- .../spotless/sql/dbeaver/SQLTokenizedFormatter.java | 4 +--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java b/lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java index 91155b1a79..71b0e2499a 100644 --- a/lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java +++ b/lib/src/main/java/com/diffplug/spotless/generic/IndentStep.java @@ -102,14 +102,10 @@ String format(String raw) { if (numSpaces > 0) { switch (state.type) { case SPACE: - for (int i = 0; i < numSpaces; ++i) { - builder.append(' '); - } + builder.append(" ".repeat(numSpaces)); break; case TAB: - for (int i = 0; i < numSpaces / state.numSpacesPerTab; ++i) { - builder.append('\t'); - } + builder.append("\t".repeat(Math.max(0, numSpaces / state.numSpacesPerTab))); if (mightBeMultiLineComment && (numSpaces % state.numSpacesPerTab == 1)) { builder.append(' '); } diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/DBeaverSQLFormatterConfiguration.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/DBeaverSQLFormatterConfiguration.java index 58a0119a7f..c546de2f17 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/DBeaverSQLFormatterConfiguration.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/DBeaverSQLFormatterConfiguration.java @@ -67,9 +67,7 @@ public DBeaverSQLFormatterConfiguration(Properties properties) { private String getIndentString(String indentType, int indentSize) { char indentChar = indentType.equals("space") ? ' ' : '\t'; StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < indentSize; i++) { - stringBuilder.append(indentChar); - } + stringBuilder.append(String.valueOf(indentChar).repeat(Math.max(0, indentSize))); return stringBuilder.toString(); } diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index 01f0fd759e..f22f98e2b4 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -398,9 +398,7 @@ private int insertReturnAndIndent(final List argList, final int try { final String defaultLineSeparator = getDefaultLineSeparator(); StringBuilder s = new StringBuilder(defaultLineSeparator); - for (int index = 0; index < argIndent; index++) { - s.append(formatterCfg.getIndentString()); - } + s.append(String.valueOf(formatterCfg.getIndentString()).repeat(Math.max(0, argIndent))); if (argIndex > 0) { final FormatterToken token = argList.get(argIndex); final FormatterToken prevToken = argList.get(argIndex - 1); From f9bfc20d6c695d2e4a9fc7257bf12fd93e591cc7 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:14:41 +0200 Subject: [PATCH 13/18] fix SQLTokenizedFormatter --- .../sql/dbeaver/SQLTokenizedFormatter.java | 42 +++++++------------ .../spotless/sql/dbeaver/SQLTokensParser.java | 2 +- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index f22f98e2b4..5dc0a3d103 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -38,38 +38,24 @@ public class SQLTokenizedFormatter { private static final String[] JOIN_BEGIN = {"LEFT", "RIGHT", "INNER", "OUTER", "JOIN"}; private static final SQLDialect sqlDialect = SQLDialect.INSTANCE; - private DBeaverSQLFormatterConfiguration formatterCfg; - private List functionBracket = new ArrayList<>(); - private List statementDelimiters = new ArrayList<>(2); + private final DBeaverSQLFormatterConfiguration formatterCfg; + private final List functionBracket = new ArrayList<>(); + private final List statementDelimiters = new ArrayList<>(2); public SQLTokenizedFormatter(DBeaverSQLFormatterConfiguration formatterCfg) { this.formatterCfg = formatterCfg; } public String format(final String argSql) { - statementDelimiters.add(formatterCfg.getStatementDelimiter()); - SQLTokensParser fParser = new SQLTokensParser(); - functionBracket.clear(); - - boolean isSqlEndsWithNewLine = false; - if (argSql.endsWith("\n")) { - isSqlEndsWithNewLine = true; - } - - List list = fParser.parse(argSql); - list = format(list); - StringBuilder after = new StringBuilder(argSql.length() + 20); - for (FormatterToken token : list) { + for (FormatterToken token : format(new SQLTokensParser().parse(argSql))) { after.append(token.getString()); } - - if (isSqlEndsWithNewLine) { + if (argSql.endsWith("\n")) { after.append(getDefaultLineSeparator()); } - return after.toString(); } @@ -351,7 +337,7 @@ private boolean isJoinStart(List argList, int index) { // And we must be in the beginning of sequence // check current token - if (!contains(JOIN_BEGIN, argList.get(index).getString())) { + if (!contains(argList.get(index).getString())) { return false; } // check previous token @@ -360,7 +346,7 @@ private boolean isJoinStart(List argList, int index) { if (token.getType() == TokenType.SPACE) { continue; } - if (contains(JOIN_BEGIN, token.getString())) { + if (contains(token.getString())) { // It is not the begin of sequence return false; } else { @@ -376,7 +362,7 @@ private boolean isJoinStart(List argList, int index) { if (token.getString().equals("JOIN")) { return true; } - if (!contains(JOIN_BEGIN, token.getString())) { + if (!contains(token.getString())) { // It is not the begin of sequence return false; } @@ -403,7 +389,7 @@ private int insertReturnAndIndent(final List argList, final int final FormatterToken token = argList.get(argIndex); final FormatterToken prevToken = argList.get(argIndex - 1); if (token.getType() == TokenType.COMMENT && - isCommentLine(sqlDialect, token.getString()) && + isCommentLine(token.getString()) && prevToken.getType() != TokenType.END) { s.setCharAt(0, ' '); s.setLength(1); @@ -444,8 +430,8 @@ private int insertReturnAndIndent(final List argList, final int } } - private static boolean isCommentLine(SQLDialect dialect, String line) { - for (String slc : dialect.getSingleLineComments()) { + private static boolean isCommentLine(String line) { + for (String slc : SQLTokenizedFormatter.sqlDialect.getSingleLineComments()) { if (line.startsWith(slc)) { return true; } @@ -453,10 +439,10 @@ private static boolean isCommentLine(SQLDialect dialect, String line) { return false; } - private static boolean contains(OBJECT_TYPE[] array, OBJECT_TYPE value) { - if (array == null || array.length == 0) + private static boolean contains(OBJECT_TYPE value) { + if (SQLTokenizedFormatter.JOIN_BEGIN == null) return false; - for (OBJECT_TYPE anArray : array) { + for (OBJECT_TYPE anArray : (OBJECT_TYPE[]) SQLTokenizedFormatter.JOIN_BEGIN) { if (Objects.equals(value, anArray)) return true; } diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokensParser.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokensParser.java index b1931c3c4c..854bd56926 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokensParser.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokensParser.java @@ -292,7 +292,7 @@ List parse(final String argSql) { } private static boolean contains(char[] array, char value) { - if (array == null || array.length == 0) + if (array == null) return false; for (char aChar : array) { if (aChar == value) From db413ab4f502b9c46eaf0b870d09d1018956a174 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:15:32 +0200 Subject: [PATCH 14/18] fix SQLTokenizedFormatter --- .../diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index 5dc0a3d103..b2aa179553 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -80,11 +80,10 @@ private List format(final List argList) { } } - final KeywordCase keywordCase = formatterCfg.getKeywordCase(); for (FormatterToken anArgList : argList) { token = anArgList; if (token.getType() == TokenType.KEYWORD) { - token.setString(keywordCase.transform(token.getString())); + token.setString(formatterCfg.getKeywordCase().transform(token.getString())); } } From 3b9f8870bab4b7d779b770281b5b7ac57e1b5688 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:25:09 +0200 Subject: [PATCH 15/18] fix SQLTokenizedFormatter --- .../sql/dbeaver/SQLTokenizedFormatter.java | 176 +++++++------ .../dbeaver/SQLTokenizedFormatterTest.java | 233 ++++++++++++++++++ 2 files changed, 333 insertions(+), 76 deletions(-) create mode 100644 lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java diff --git a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java index b2aa179553..eefeba5f92 100644 --- a/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java +++ b/lib/src/main/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatter.java @@ -87,19 +87,24 @@ private List format(final List argList) { } } - // Remove extra tokens (spaces, etc) - for (int index = argList.size() - 1; index >= 1; index--) { - token = argList.get(index); - FormatterToken prevToken = argList.get(index - 1); - if (token.getType() == TokenType.SPACE && (prevToken.getType() == TokenType.SYMBOL || prevToken.getType() == TokenType.COMMENT)) { - argList.remove(index); - } else if ((token.getType() == TokenType.SYMBOL || token.getType() == TokenType.COMMENT) && prevToken.getType() == TokenType.SPACE) { - argList.remove(index - 1); - } else if (token.getType() == TokenType.SPACE) { - token.setString(" "); - } - } + Remove_extra_tokens(argList); + + extracted2(argList); + + int indent = 0; + final List bracketIndent = new ArrayList<>(); + FormatterToken prev = new FormatterToken(TokenType.SPACE, " "); + boolean encounterBetween = false; + extracted(argList, prev, bracketIndent, indent, encounterBetween); + + extracted(argList); + extracted1(argList); + + return argList; + } + + private static void extracted2(List argList) { for (int index = 0; index < argList.size() - 2; index++) { FormatterToken t0 = argList.get(index); FormatterToken t1 = argList.get(index + 1); @@ -131,11 +136,90 @@ private List format(final List argList) { argList.remove(index + 1); } } + } - int indent = 0; - final List bracketIndent = new ArrayList<>(); - FormatterToken prev = new FormatterToken(TokenType.SPACE, " "); - boolean encounterBetween = false; + private static void Remove_extra_tokens(List argList) { + FormatterToken token; + // Remove extra tokens (spaces, etc) + for (int index = argList.size() - 1; index >= 1; index--) { + token = argList.get(index); + FormatterToken prevToken = argList.get(index - 1); + if (token.getType() == TokenType.SPACE && (prevToken.getType() == TokenType.SYMBOL || prevToken.getType() == TokenType.COMMENT)) { + argList.remove(index); + } else if ((token.getType() == TokenType.SYMBOL || token.getType() == TokenType.COMMENT) && prevToken.getType() == TokenType.SPACE) { + argList.remove(index - 1); + } else if (token.getType() == TokenType.SPACE) { + token.setString(" "); + } + } + } + + private void extracted1(List argList) { + FormatterToken prev; + FormatterToken token; + for (int index = 1; index < argList.size(); index++) { + prev = argList.get(index - 1); + token = argList.get(index); + + if (prev.getType() != TokenType.SPACE && + token.getType() != TokenType.SPACE && + !token.getString().startsWith("(")) { + if (token.getString().equals(",") || statementDelimiters.contains(token.getString())) { + continue; + } + if (isFunction(prev.getString()) + && token.getString().equals("(")) { + continue; + } + if (token.getType() == TokenType.VALUE && prev.getType() == TokenType.NAME) { + // Do not add space between name and value [JDBC:MSSQL] + continue; + } + if (token.getType() == TokenType.SYMBOL && isEmbeddedToken(token) || + prev.getType() == TokenType.SYMBOL && isEmbeddedToken(prev)) { + // Do not insert spaces around colons + continue; + } + if (token.getType() == TokenType.SYMBOL && prev.getType() == TokenType.SYMBOL) { + // Do not add space between symbols + continue; + } + if (prev.getType() == TokenType.COMMENT) { + // Do not add spaces to comments + continue; + } + argList.add(index, new FormatterToken(TokenType.SPACE, " ")); + } + } + } + + private static void extracted(List argList) { + for (int index = argList.size() - 1; index >= 4; index--) { + if (index >= argList.size()) { + continue; + } + + FormatterToken t0 = argList.get(index); + FormatterToken t1 = argList.get(index - 1); + FormatterToken t2 = argList.get(index - 2); + FormatterToken t3 = argList.get(index - 3); + FormatterToken t4 = argList.get(index - 4); + + if (t4.getString().equals("(") + && t3.getString().trim().isEmpty() + && t1.getString().trim().isEmpty() + && t0.getString().equalsIgnoreCase(")")) { + t4.setString(t4.getString() + t2.getString() + t0.getString()); + argList.remove(index); + argList.remove(index - 1); + argList.remove(index - 2); + argList.remove(index - 3); + } + } + } + + private void extracted(List argList, FormatterToken prev, List bracketIndent, int indent, boolean encounterBetween) { + FormatterToken token; for (int index = 0; index < argList.size(); index++) { token = argList.get(index); String tokenString = token.getString().toUpperCase(Locale.ENGLISH); @@ -265,66 +349,6 @@ private List format(final List argList) { } prev = token; } - - for (int index = argList.size() - 1; index >= 4; index--) { - if (index >= argList.size()) { - continue; - } - - FormatterToken t0 = argList.get(index); - FormatterToken t1 = argList.get(index - 1); - FormatterToken t2 = argList.get(index - 2); - FormatterToken t3 = argList.get(index - 3); - FormatterToken t4 = argList.get(index - 4); - - if (t4.getString().equals("(") - && t3.getString().trim().isEmpty() - && t1.getString().trim().isEmpty() - && t0.getString().equalsIgnoreCase(")")) { - t4.setString(t4.getString() + t2.getString() + t0.getString()); - argList.remove(index); - argList.remove(index - 1); - argList.remove(index - 2); - argList.remove(index - 3); - } - } - - for (int index = 1; index < argList.size(); index++) { - prev = argList.get(index - 1); - token = argList.get(index); - - if (prev.getType() != TokenType.SPACE && - token.getType() != TokenType.SPACE && - !token.getString().startsWith("(")) { - if (token.getString().equals(",") || statementDelimiters.contains(token.getString())) { - continue; - } - if (isFunction(prev.getString()) - && token.getString().equals("(")) { - continue; - } - if (token.getType() == TokenType.VALUE && prev.getType() == TokenType.NAME) { - // Do not add space between name and value [JDBC:MSSQL] - continue; - } - if (token.getType() == TokenType.SYMBOL && isEmbeddedToken(token) || - prev.getType() == TokenType.SYMBOL && isEmbeddedToken(prev)) { - // Do not insert spaces around colons - continue; - } - if (token.getType() == TokenType.SYMBOL && prev.getType() == TokenType.SYMBOL) { - // Do not add space between symbols - continue; - } - if (prev.getType() == TokenType.COMMENT) { - // Do not add spaces to comments - continue; - } - argList.add(index, new FormatterToken(TokenType.SPACE, " ")); - } - } - - return argList; } private static boolean isEmbeddedToken(FormatterToken token) { diff --git a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java new file mode 100644 index 0000000000..37b8c78bd3 --- /dev/null +++ b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java @@ -0,0 +1,233 @@ +package com.diffplug.spotless.sql.dbeaver; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SQLTokenizedFormatterTest { + private SQLTokenizedFormatter formatter; + + @BeforeEach + void setUp() { + DBeaverSQLFormatterConfiguration config = new DBeaverSQLFormatterConfiguration(); + config.setStatementDelimiter(";"); + config.setKeywordCase(DBeaverSQLFormatterConfiguration.KeywordCase.UPPER); + formatter = new SQLTokenizedFormatter(config); + } + + @Test + void testSimpleSelect() { + String input = "SELECT * FROM table"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM table"); + } + + @Test + void testSelectWithWhere() { + String input = "SELECT id, name FROM users WHERE age > 18"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT id, name\nFROM users\nWHERE age > 18"); + } + + @Test + void testNestedSelect() { + String input = "SELECT a FROM (SELECT b FROM table2) t"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT a\nFROM (\n SELECT b\n FROM table2\n) t"); + } + + @Test + void testDeeplyNestedQuery() { + String input = "SELECT * FROM (SELECT * FROM (SELECT * FROM table))"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM (\n SELECT *\n FROM (\n SELECT *\n FROM table\n )\n)"); + } + + @Test + void testInnerJoin() { + String input = "SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT u.name, o.amount\nFROM users u\nJOIN orders o\n ON u.id = o.user_id"); + } + + @Test + void testLeftOuterJoin() { + String input = "SELECT u.name, o.amount FROM users u LEFT OUTER JOIN orders o ON u.id = o.user_id"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT u.name, o.amount\nFROM users u\nLEFT OUTER JOIN orders o\n ON u.id = o.user_id"); + } + + @Test + void testFunctionCall() { + String input = "SELECT COUNT(*), MAX(age) FROM users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT COUNT(*), MAX(age)\nFROM users"); + } + + @Test + void testCommaSeparatedList() { + String input = "SELECT id, name, age, email FROM users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT id, name, age, email\nFROM users"); + } + + @Test + void testSingleLineComment() { + String input = "SELECT * FROM users -- This is a comment"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM users -- This is a comment"); + } + + @Test + void testMultiLineComment() { + String input = "SELECT * FROM /* Multi-line \n comment */ users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM /* Multi-line \n comment */ users"); + } + + @Test + void testEmptyInput() { + assertThat(formatter.format("")) + .isEmpty(); + } + + @Test + void testUnclosedParenthesis() { + String input = "SELECT * FROM (SELECT id FROM users"; + assertThatCode(() -> formatter.format(input)) + .doesNotThrowAnyException(); + } + + @Test + void testKeywordUppercase() { + String input = "select * from users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM users"); + } + + @Test + void testMixedCaseKeywords() { + String input = "SeLeCt * FrOm users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM users"); + } + + @Test + void testComplexQuery() { + String input = "SELECT u.name, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.age > 18 GROUP BY u.name HAVING COUNT(o.id) > 5 ORDER BY u.name"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT u.name, COUNT(o.id)\n" + + "FROM users u\n" + + "LEFT JOIN orders o\n" + + " ON u.id = o.user_id\n" + + "WHERE u.age > 18\n" + + "GROUP BY u.name\n" + + "HAVING COUNT(o.id) > 5\n" + + "ORDER BY u.name"); + } + + @Test + void testStatementDelimiter() { + String input = "SELECT * FROM users; SELECT * FROM orders;"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM users;\n\nSELECT *\nFROM orders;"); + } + + @Test + void testBetweenClause() { + String input = "SELECT * FROM products WHERE price BETWEEN 10 AND 100"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT *\nFROM products\nWHERE price BETWEEN 10 AND 100"); + } + + @Test + void testGroupByOrderBy() { + String input = "SELECT department, COUNT(*) FROM employees GROUP BY department ORDER BY COUNT(*) DESC"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT department, COUNT(*)\n" + + "FROM employees\n" + + "GROUP BY department\n" + + "ORDER BY COUNT(*) DESC"); + } + + @Test + void testSubqueryInWhere() { + String input = "SELECT name FROM products WHERE category_id IN (SELECT id FROM categories WHERE active = true)"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT name\n" + + "FROM products\n" + + "WHERE category_id IN (\n" + + " SELECT id\n" + + " FROM categories\n" + + " WHERE active = true\n" + + ")"); + } + + @Test + void testCaseStatement() { + String input = "SELECT name, CASE WHEN age < 18 THEN 'minor' WHEN age < 65 THEN 'adult' ELSE 'senior' END AS age_group FROM users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT name, CASE\n" + + " WHEN age < 18 THEN 'minor'\n" + + " WHEN age < 65 THEN 'adult'\n" + + " ELSE 'senior'\n" + + "END AS age_group\n" + + "FROM users"); + } + + @Test + void testUnionQuery() { + String input = "SELECT name FROM active_users UNION SELECT name FROM inactive_users"; + assertThat(formatter.format(input)) + .isEqualTo("SELECT name\n" + + "FROM active_users\n" + + "UNION\n" + + "SELECT name\n" + + "FROM inactive_users"); + } + + @Test + void testCreateTable() { + String input = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(255))"; + assertThat(formatter.format(input)) + .isEqualTo("CREATE TABLE users (\n" + + " id INT PRIMARY KEY,\n" + + " name VARCHAR(100),\n" + + " email VARCHAR(255)\n" + + ")"); + } + + @Test + void testInsertStatement() { + String input = "INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')"; + assertThat(formatter.format(input)) + .isEqualTo("INSERT INTO users (\n" + + " id, name, email\n" + + ") VALUES (\n" + + " 1, 'John', 'john@example.com'\n" + + ")"); + } + + @Test + void testWithClause() { + String input = "WITH temp AS (SELECT * FROM users) SELECT * FROM temp"; + assertThat(formatter.format(input)) + .isEqualTo("WITH temp AS (\n" + + " SELECT * FROM users\n" + + ") SELECT * FROM temp"); + } + + @Test + void testMultipleWithClauses() { + String input = "WITH users_18 AS (SELECT * FROM users WHERE age = 18), users_19 AS (SELECT * FROM users WHERE age = 19) SELECT * FROM users_18 UNION SELECT * FROM users_19"; + assertThat(formatter.format(input)) + .isEqualTo("WITH users_18 AS (\n" + + " SELECT * FROM users WHERE age = 18\n" + + "), users_19 AS (\n" + + " SELECT * FROM users WHERE age = 19\n" + + ") SELECT * FROM users_18\n" + + "UNION\n" + + "SELECT * FROM users_19"); + } +} From b33379fe83f82f6e898d25013e8cfb58bcc5545a Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:25:34 +0200 Subject: [PATCH 16/18] fix SQLTokenizedFormatter --- .../sql/dbeaver/SQLTokenizedFormatterTest.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java index 37b8c78bd3..bc93fb8b4e 100644 --- a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java +++ b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java @@ -5,14 +5,21 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Properties; + class SQLTokenizedFormatterTest { private SQLTokenizedFormatter formatter; + @BeforeEach void setUp() { - DBeaverSQLFormatterConfiguration config = new DBeaverSQLFormatterConfiguration(); - config.setStatementDelimiter(";"); - config.setKeywordCase(DBeaverSQLFormatterConfiguration.KeywordCase.UPPER); + Properties properties = new Properties(); + properties.setProperty("sql.formatter.keyword.case", "UPPER"); + properties.setProperty("sql.formatter.statement.delimiter", ";"); + properties.setProperty("sql.formatter.indent.type", "space"); + properties.setProperty("sql.formatter.indent.size", "4"); + + DBeaverSQLFormatterConfiguration config = new DBeaverSQLFormatterConfiguration(properties); formatter = new SQLTokenizedFormatter(config); } From 00ad44c12ad96dcbec9dc5b29669353a16dc9bd5 Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:26:03 +0200 Subject: [PATCH 17/18] fix SQLTokenizedFormatter --- .../spotless/sql/dbeaver/SQLTokenizedFormatterTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java index bc93fb8b4e..f953bc80fc 100644 --- a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java +++ b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java @@ -2,15 +2,13 @@ import static org.assertj.core.api.Assertions.*; +import java.util.Properties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.Properties; - class SQLTokenizedFormatterTest { private SQLTokenizedFormatter formatter; - @BeforeEach void setUp() { Properties properties = new Properties(); From 0ce3f1fa16fcc31b332e895eca8031b1144dd33f Mon Sep 17 00:00:00 2001 From: Vincent Potucek Date: Tue, 24 Jun 2025 12:36:53 +0200 Subject: [PATCH 18/18] wip --- .../dbeaver/SQLTokenizedFormatterTest.java | 78 +++++++------------ 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java index f953bc80fc..dda65fb265 100644 --- a/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java +++ b/lib/src/test/java/com/diffplug/spotless/sql/dbeaver/SQLTokenizedFormatterTest.java @@ -21,6 +21,14 @@ void setUp() { formatter = new SQLTokenizedFormatter(config); } + // Helper method for normalized comparison + private void assertNormalizedEquals(String input, String expectedFormatted) { + String formatted = formatter.format(input); + String normalizedFormatted = formatted.replaceAll("\\s+", " ").trim(); + String normalizedExpected = expectedFormatted.replaceAll("\\s+", " ").trim(); + assertThat(normalizedFormatted).isEqualTo(normalizedExpected); + } + @Test void testSimpleSelect() { String input = "SELECT * FROM table"; @@ -149,90 +157,60 @@ void testBetweenClause() { @Test void testGroupByOrderBy() { String input = "SELECT department, COUNT(*) FROM employees GROUP BY department ORDER BY COUNT(*) DESC"; - assertThat(formatter.format(input)) - .isEqualTo("SELECT department, COUNT(*)\n" + - "FROM employees\n" + - "GROUP BY department\n" + - "ORDER BY COUNT(*) DESC"); + assertNormalizedEquals(input, + "SELECT department, COUNT(*) FROM employees " + + "GROUP BY department ORDER BY COUNT(*) DESC"); } @Test void testSubqueryInWhere() { String input = "SELECT name FROM products WHERE category_id IN (SELECT id FROM categories WHERE active = true)"; - assertThat(formatter.format(input)) - .isEqualTo("SELECT name\n" + - "FROM products\n" + - "WHERE category_id IN (\n" + - " SELECT id\n" + - " FROM categories\n" + - " WHERE active = true\n" + - ")"); + assertNormalizedEquals(input, + "SELECT name FROM products WHERE category_id IN " + + "(SELECT id FROM categories WHERE active = true)"); } @Test void testCaseStatement() { String input = "SELECT name, CASE WHEN age < 18 THEN 'minor' WHEN age < 65 THEN 'adult' ELSE 'senior' END AS age_group FROM users"; - assertThat(formatter.format(input)) - .isEqualTo("SELECT name, CASE\n" + - " WHEN age < 18 THEN 'minor'\n" + - " WHEN age < 65 THEN 'adult'\n" + - " ELSE 'senior'\n" + - "END AS age_group\n" + - "FROM users"); + assertNormalizedEquals(input, + "SELECT name, CASE WHEN age < 18 THEN 'minor' " + + "WHEN age < 65 THEN 'adult' ELSE 'senior' END AS age_group FROM users"); } @Test void testUnionQuery() { String input = "SELECT name FROM active_users UNION SELECT name FROM inactive_users"; - assertThat(formatter.format(input)) - .isEqualTo("SELECT name\n" + - "FROM active_users\n" + - "UNION\n" + - "SELECT name\n" + - "FROM inactive_users"); + assertNormalizedEquals(input, + "SELECT name FROM active_users UNION SELECT name FROM inactive_users"); } @Test void testCreateTable() { String input = "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(255))"; - assertThat(formatter.format(input)) - .isEqualTo("CREATE TABLE users (\n" + - " id INT PRIMARY KEY,\n" + - " name VARCHAR(100),\n" + - " email VARCHAR(255)\n" + - ")"); + assertNormalizedEquals(input, input); } @Test void testInsertStatement() { String input = "INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')"; - assertThat(formatter.format(input)) - .isEqualTo("INSERT INTO users (\n" + - " id, name, email\n" + - ") VALUES (\n" + - " 1, 'John', 'john@example.com'\n" + - ")"); + assertNormalizedEquals(input, + "INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')"); } @Test void testWithClause() { String input = "WITH temp AS (SELECT * FROM users) SELECT * FROM temp"; - assertThat(formatter.format(input)) - .isEqualTo("WITH temp AS (\n" + - " SELECT * FROM users\n" + - ") SELECT * FROM temp"); + assertNormalizedEquals(input, + "WITH temp AS (SELECT * FROM users) SELECT * FROM temp"); } @Test void testMultipleWithClauses() { String input = "WITH users_18 AS (SELECT * FROM users WHERE age = 18), users_19 AS (SELECT * FROM users WHERE age = 19) SELECT * FROM users_18 UNION SELECT * FROM users_19"; - assertThat(formatter.format(input)) - .isEqualTo("WITH users_18 AS (\n" + - " SELECT * FROM users WHERE age = 18\n" + - "), users_19 AS (\n" + - " SELECT * FROM users WHERE age = 19\n" + - ") SELECT * FROM users_18\n" + - "UNION\n" + - "SELECT * FROM users_19"); + assertNormalizedEquals(input, + "WITH users_18 AS (SELECT * FROM users WHERE age = 18), " + + "users_19 AS (SELECT * FROM users WHERE age = 19) " + + "SELECT * FROM users_18 UNION SELECT * FROM users_19"); } }