options() {
+ return options_;
+ }
+
+ /**
+ * Sets the output file.
*
- * ATTENTION: generated result will have few queries, joined by pipe(|). Together they will match all AST nodes
- * on specified line and column. You need to choose only one and recheck that it works. Usage of all of them is also
- * ok, but might result in undesirable matching and suppress other issues.
+ * Defaults to stdout.
*
- * @param lineColumn the line column
+ * @param file the output file
* @return the checkstyle operation
*/
- public CheckstyleOperation lineColumn(String lineColumn) {
- if (isNotBlank(lineColumn)) {
- options.put("-s", lineColumn);
+ public CheckstyleOperation outputPath(String file) {
+ if (isNotBlank(file)) {
+ options_.put("-o", file);
}
return this;
}
/**
- * Sets the output file. Defaults to stdout.
+ * Sets the output file.
+ *
+ * Defaults to stdout.
*
- * @param file the file
+ * @param file the output file
* @return the checkstyle operation
*/
- public CheckstyleOperation output(String file) {
- if (isNotBlank(file)) {
- options.put("-o", file);
- }
- return this;
+ public CheckstyleOperation outputPath(File file) {
+ return outputPath(file.getAbsolutePath());
+ }
+
+ /**
+ * Sets the output file.
+ *
+ * Defaults to stdout.
+ *
+ * @param file the output file
+ * @return the checkstyle operation
+ */
+ public CheckstyleOperation outputPath(Path file) {
+ return outputPath(file.toFile().getAbsolutePath());
}
/**
@@ -287,93 +412,184 @@ public class CheckstyleOperation extends AbstractProcessOperation dirs) {
+ sourceDir_.addAll(dirs);
return this;
}
/**
- * Specified the file(s) or folder(s) containing the source files to check.
+ * Returns the file(s) or folders(s) containing the sources files to check
+ *
+ * @return the files or directories
+ */
+ public Set sourceDir() {
+ return sourceDir_;
+ }
+
+ /**
+ * Specifies the file(s) or folder(s) containing the source files to check.
+ *
+ * @param dirs the directories
+ * @return the checkstyle operation
+ * @see #sourceDir(Path...)
+ */
+ public CheckstyleOperation sourceDirPaths(Collection dirs) {
+ return sourceDir(dirs.stream().map(Path::toFile).toList());
+ }
+
+ /**
+ * Specifies the file(s) or folder(s) containing the source files to check.
*
* @param dirs the directories
* @return the checkstyle operation
* @see #sourceDir(String...)
*/
- public CheckstyleOperation sourceDir(Collection dirs) {
- sourceDirs.addAll(dirs.stream().filter(this::isNotBlank).toList());
+ public CheckstyleOperation sourceDirStrings(Collection dirs) {
+ return sourceDir(dirs.stream().map(File::new).toList());
+ }
+
+ /**
+ * Prints xpath suppressions at the file's line and column position. Argument is the line and column number
+ * (separated by a {@code :} ) in the file that the suppression should be generated for. The option cannot be
+ * used with other options and requires exactly one file to run on to be specified.
+ *
+ * Note that the generated result will have few queries, joined by pipe({@code |}). Together they will match all
+ * AST nodes on specified line and column. You need to choose only one and recheck that it works. Usage of all of
+ * them is also ok, but might result in undesirable matching and suppress other issues.
+ *
+ * @param lineColumnNumber the line column number
+ * @return the checkstyle operation
+ */
+ public CheckstyleOperation suppressionLineColumnNumber(String lineColumnNumber) {
+ if (isNotBlank(lineColumnNumber)) {
+ options_.put("-s", lineColumnNumber);
+ }
return this;
}
/**
- * Sets the length of the tab character. Used only with the {@link #lineColumn(String) lineColum} option.
+ * Sets the length of the tab character. Used only with the
+ * {@link #suppressionLineColumnNumber(String) suppressionLineColumnNumber} option.
+ *
* Default value is {@code 8}.
*
* @param length the length
* @return the checkstyle operation
*/
public CheckstyleOperation tabWith(int length) {
- options.put("-w", String.valueOf(length));
+ options_.put("-w", String.valueOf(length));
return this;
}
/**
- * Prints Abstract Syntax Tree(AST) of the checked file. The option cannot be used other options and requires
- * exactly one file to run on to be specified.
+ * This option is used to display the Abstract Syntax Tree (AST) without any comments of the specified file. It can
+ * only be used on a single file and cannot be combined with other options.
*
* @param isTree {@code true} or {@code false}
* @return the checkstyle operation
*/
public CheckstyleOperation tree(boolean isTree) {
if (isTree) {
- options.put("-t", "");
+ options_.put("-t", "");
} else {
- options.remove("-t");
+ options_.remove("-t");
}
return this;
}
/**
- * Prints Abstract Syntax Tree(AST) with comment nodes of the checked file. The option cannot be used with other
- * options and requires exactly one file to run on to be specified.
+ * This option is used to display the Abstract Syntax Tree (AST) with comment nodes excluding Javadoc of the
+ * specified file. It can only be used on a single file and cannot be combined with other options.
*
* @param isTree {@code true} or {@code false}
* @return the checkstyle operation
*/
public CheckstyleOperation treeWithComments(boolean isTree) {
if (isTree) {
- options.put("-T", "");
+ options_.put("-T", "");
} else {
- options.remove("-T");
+ options_.remove("-T");
}
return this;
}
/**
- * Prints Abstract Syntax Tree(AST) with Javadoc nodes and comment nodes of the checked file. Attention that line
- * number and columns will not be the same as it is a file due to the fact that each javadoc comment is parsed
- * separately from java file. The option cannot be used with other options and requires exactly one file to run on
- * to be specified.
+ * This option is used to display the Abstract Syntax Tree (AST) with Javadoc nodes of the specified file. It can
+ * only be used on a single file and cannot be combined with other options.
*
* @param isTree {@code true} or {@code false}
* @return the checkstyle operation
*/
public CheckstyleOperation treeWithJavadoc(boolean isTree) {
if (isTree) {
- options.put("-J", "");
+ options_.put("-J", "");
} else {
- options.remove("-J");
+ options_.remove("-J");
}
return this;
}
diff --git a/src/main/java/rife/bld/extension/checkstyle/OutputFormat.java b/src/main/java/rife/bld/extension/checkstyle/OutputFormat.java
new file mode 100644
index 0000000..0ba8021
--- /dev/null
+++ b/src/main/java/rife/bld/extension/checkstyle/OutputFormat.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2023-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rife.bld.extension.checkstyle;
+
+/**
+ * The Checkstyle output format for XML, sarif and default (plain) logger.
+ */
+public enum OutputFormat {
+ XML("xml"),
+ SARIF("sarif"),
+ PLAIN("plain");
+
+ public final String label;
+
+ /**
+ * Sets the label of this output format.
+ */
+ OutputFormat(String label) {
+ this.label = label;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/rife/bld/extension/CheckstyleOperationTest.java b/src/test/java/rife/bld/extension/CheckstyleOperationTest.java
index 6bd2233..0d0e1b2 100644
--- a/src/test/java/rife/bld/extension/CheckstyleOperationTest.java
+++ b/src/test/java/rife/bld/extension/CheckstyleOperationTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,58 +16,150 @@
package rife.bld.extension;
+import org.assertj.core.api.AutoCloseableSoftAssertions;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
import rife.bld.BaseProject;
import rife.bld.Project;
import rife.bld.WebProject;
+import rife.bld.extension.checkstyle.OutputFormat;
import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.List;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
-
class CheckstyleOperationTest {
+ public static final String SRC_MAIN_JAVA = "src/main/java";
+ public static final String SRC_TEST_JAVA = "src/test/java";
private static final String ADD = "add";
private static final String BAR = "bar";
private static final String FOO = "foo";
private static final String REMOVE = "remove";
+ @BeforeAll
+ static void beforeAll() {
+ var level = Level.ALL;
+ var logger = Logger.getLogger("rife.bld.extension");
+ var consoleHandler = new ConsoleHandler();
+ consoleHandler.setLevel(level);
+ logger.addHandler(consoleHandler);
+ logger.setLevel(level);
+ logger.setUseParentHandlers(false);
+ }
+
+
@Test
void branchMatchingXpath() {
var op = new CheckstyleOperation().fromProject(new Project()).branchMatchingXpath(FOO);
- assertThat(op.options.get("-b")).isEqualTo(FOO);
+ assertThat(op.options().get("-b")).isEqualTo(FOO);
+ }
+
+ @Test
+ @EnabledOnOs(OS.LINUX)
+ void checkAllParameters() throws IOException {
+ var args = Files.readAllLines(Paths.get("src", "test", "resources", "checkstyle-args.txt"));
+
+ assertThat(args).isNotEmpty();
+
+ var params = new CheckstyleOperation()
+ .fromProject(new Project())
+ .branchMatchingXpath("xpath")
+ .debug(true)
+ .configurationFile(new File("config"))
+ .exclude(SRC_MAIN_JAVA)
+ .excludeRegex("regex")
+ .executeIgnoredModules(true)
+ .format(OutputFormat.XML)
+ .generateXpathSuppression(true)
+ .javadocTree(true)
+ .outputPath(new File("optionPath"))
+ .propertiesFile(new File("properties"))
+ .suppressionLineColumnNumber("12")
+ .tabWith(1)
+ .tree(true)
+ .treeWithComments(true)
+ .treeWithJavadoc(true)
+ .executeConstructProcessCommandList();
+
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ for (var p : args) {
+ var found = false;
+ for (var a : params) {
+ if (a.startsWith(p)) {
+ found = true;
+ break;
+ }
+ }
+ softly.assertThat(found).as(p + " not found.").isTrue();
+ }
+ }
}
@Test
void configurationFile() {
var op = new CheckstyleOperation().fromProject(new Project()).configurationFile(FOO);
- assertThat(op.options.get("-c")).isEqualTo(FOO);
+ assertThat(op.options().get("-c")).isEqualTo(FOO);
}
@Test
void debug() {
var op = new CheckstyleOperation().fromProject(new Project()).debug(true);
- assertThat(op.options.containsKey("-d")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-d")).as(ADD).isTrue();
op = op.debug(false);
- assertThat(op.options.containsKey("-d")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-d")).as(REMOVE).isFalse();
}
@Test
void exclude() {
- var op = new CheckstyleOperation().fromProject(new Project()).exclude(FOO);
- assertThat(op.options.get("-e")).isEqualTo(FOO);
- op = new CheckstyleOperation().fromProject(new Project()).exclude(List.of(FOO));
- assertThat(op.options.get("-e")).as("as list").isEqualTo(FOO);
+ var foo = new File(SRC_MAIN_JAVA);
+ var bar = new File(SRC_TEST_JAVA);
+ var e = "-e ";
+
+ var op = new CheckstyleOperation().fromProject(new Project()).exclude(SRC_MAIN_JAVA, SRC_TEST_JAVA);
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("String...")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
+
+ op = new CheckstyleOperation().fromProject(new Project()).excludeStrings(List.of(SRC_MAIN_JAVA, SRC_TEST_JAVA));
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("List(String...)")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
+
+ op = new CheckstyleOperation().fromProject(new Project()).exclude(foo, bar);
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("File...")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
+
+ op = new CheckstyleOperation().fromProject(new Project()).exclude(List.of(foo, bar));
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("List(File...)")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
+
+ op = new CheckstyleOperation().fromProject(new Project()).exclude(foo.toPath(), bar.toPath());
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("Path...")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
+
+ op = new CheckstyleOperation().fromProject(new Project()).excludePaths(List.of(foo.toPath(), bar.toPath()));
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("List(Path...)")
+ .contains(e + foo.getAbsolutePath()).contains(e + bar.getAbsolutePath());
}
@Test
- void excludedPathPattern() {
- var op = new CheckstyleOperation().fromProject(new Project()).excludedPathPattern(FOO);
- assertThat(op.options.get("-x")).isEqualTo(FOO);
+ void excludeRegex() {
+ var op = new CheckstyleOperation().fromProject(new Project()).excludeRegex(FOO, BAR);
+ var x = "-x ";
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).contains(x + FOO, x + BAR);
+
+ op = new CheckstyleOperation().fromProject(new Project()).excludeRegex(List.of(FOO, BAR));
+ assertThat(String.join(" ", op.executeConstructProcessCommandList())).as("as list").contains(x + FOO, x + BAR);
}
@Test
@@ -76,9 +168,9 @@ class CheckstyleOperationTest {
tmpFile.deleteOnExit();
var op = new CheckstyleOperation()
.fromProject(new WebProject())
- .sourceDir("src/main/java", "src/test/java")
- .configurationFile("src/test/resources/google_checks.xml")
- .output(tmpFile.getAbsolutePath());
+ .sourceDir(SRC_MAIN_JAVA, SRC_TEST_JAVA)
+ .configurationFile(Path.of("src/test/resources/google_checks.xml"))
+ .outputPath(tmpFile.toPath());
op.execute();
assertThat(tmpFile).exists();
}
@@ -91,7 +183,7 @@ class CheckstyleOperationTest {
.propertiesFile("config/checkstyle.properties")
.debug(true)
.executeIgnoredModules(true)
- .sourceDir("src/main/java", "src/test/java");
+ .sourceDir(SRC_MAIN_JAVA, SRC_TEST_JAVA);
assertThat(String.join(" ", op.executeConstructProcessCommandList()))
.startsWith("java -cp ")
.endsWith(
@@ -100,15 +192,22 @@ class CheckstyleOperationTest {
"-b xpath " +
"-c config/checkstyle.xml " +
"-d -E " +
- "src/main/java src/test/java");
+ new File(SRC_MAIN_JAVA).getAbsolutePath() + " " +
+ new File(SRC_TEST_JAVA).getAbsolutePath());
}
@Test
void executeIgnoredModules() {
var op = new CheckstyleOperation().fromProject(new Project()).executeIgnoredModules(true);
- assertThat(op.options.containsKey("-E")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-E")).as(ADD).isTrue();
op = op.executeIgnoredModules(false);
- assertThat(op.options.containsKey("-E")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-E")).as(REMOVE).isFalse();
+ }
+
+ @Test
+ void executeNoProject() {
+ var op = new CheckstyleOperation();
+ assertThatCode(op::execute).isInstanceOf(ExitStatusException.class);
}
@Test
@@ -117,88 +216,115 @@ class CheckstyleOperationTest {
tmpFile.deleteOnExit();
var op = new CheckstyleOperation()
.fromProject(new WebProject())
- .sourceDir(List.of("src/main/java", "src/test/java"))
+ .sourceDir(SRC_MAIN_JAVA, SRC_TEST_JAVA)
.configurationFile("src/test/resources/sun_checks.xml")
- .output(tmpFile.getAbsolutePath());
+ .outputPath(tmpFile.getAbsolutePath());
assertThatCode(op::execute).isInstanceOf(ExitStatusException.class);
assertThat(tmpFile).exists();
}
@Test
void format() {
- var op = new CheckstyleOperation().fromProject(new Project()).format(FOO);
- assertThat(op.options.get("-f")).isEqualTo(FOO);
+ var op = new CheckstyleOperation().fromProject(new Project()).format(OutputFormat.XML);
+ assertThat(op.options().get("-f")).isEqualTo("xml");
}
@Test
void generateXpathSuppression() {
var op = new CheckstyleOperation().fromProject(new Project()).generateXpathSuppression(true);
- assertThat(op.options.containsKey("-g")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-g")).as(ADD).isTrue();
op = op.generateXpathSuppression(false);
- assertThat(op.options.containsKey("-g")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-g")).as(REMOVE).isFalse();
}
@Test
void javadocTree() {
var op = new CheckstyleOperation().fromProject(new Project()).javadocTree(true);
- assertThat(op.options.containsKey("-j")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-j")).as(ADD).isTrue();
op = op.javadocTree(false);
- assertThat(op.options.containsKey("-j")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-j")).as(REMOVE).isFalse();
}
@Test
- void lineColumn() {
- var op = new CheckstyleOperation().fromProject(new Project()).lineColumn(FOO);
- assertThat(op.options.get("-s")).isEqualTo(FOO);
- }
-
- @Test
- void output() {
- var op = new CheckstyleOperation().fromProject(new Project()).output(FOO);
- assertThat(op.options.get("-o")).isEqualTo(FOO);
+ void outputPath() {
+ var op = new CheckstyleOperation().fromProject(new Project()).outputPath(FOO);
+ assertThat(op.options().get("-o")).isEqualTo(FOO);
}
@Test
void propertiesFile() {
var op = new CheckstyleOperation().fromProject(new Project()).propertiesFile(FOO);
- assertThat(op.options.get("-p")).isEqualTo(FOO);
+ assertThat(op.options().get("-p")).isEqualTo(FOO);
+
+ var fooPath = Path.of(FOO);
+ op = op.propertiesFile(fooPath);
+ assertThat(op.options().get("-p")).isEqualTo(fooPath.toFile().getAbsolutePath());
}
@Test
void sourceDir() {
- var op = new CheckstyleOperation().fromProject(new Project()).sourceDir(FOO);
- assertThat(op.sourceDirs).contains(FOO);
- op = op.sourceDir(FOO, BAR);
- assertThat(op.sourceDirs).as("foo, bar").hasSize(2).contains(FOO).contains(BAR);
+ var foo = new File(FOO);
+ var bar = new File(BAR);
+
+ var op = new CheckstyleOperation().fromProject(new Project()).sourceDir(FOO, BAR);
+ assertThat(op.sourceDir()).as("String...").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+
+ op = op.sourceDirStrings(List.of(FOO, BAR));
+ assertThat(op.sourceDir()).as("List(String...)").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+
+ op = op.sourceDir(foo, bar);
+ assertThat(op.sourceDir()).as("File...").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+
+ op = op.sourceDir(List.of(foo, bar));
+ assertThat(op.sourceDir()).as("List(File...)").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+
+ op = op.sourceDir(foo.toPath(), bar.toPath());
+ assertThat(op.sourceDir()).as("Path...").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+
+ op = op.sourceDirPaths(List.of(foo.toPath(), bar.toPath()));
+ assertThat(op.sourceDir()).as("List(Path...)").hasSize(2).contains(foo, bar);
+ op.sourceDir().clear();
+ }
+
+
+ @Test
+ void suppressionLineColumnNumber() {
+ var op = new CheckstyleOperation().fromProject(new Project()).suppressionLineColumnNumber(FOO + ':' + BAR);
+ assertThat(op.options().get("-s")).isEqualTo(FOO + ':' + BAR);
}
@Test
void tabWith() {
var op = new CheckstyleOperation().fromProject(new Project()).tabWith(9);
- assertThat(op.options.get("-w")).isEqualTo("9");
+ assertThat(op.options().get("-w")).isEqualTo("9");
}
@Test
void tree() {
var op = new CheckstyleOperation().fromProject(new Project()).tree(true);
- assertThat(op.options.containsKey("-t")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-t")).as(ADD).isTrue();
op = op.tree(false);
- assertThat(op.options.containsKey("-t")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-t")).as(REMOVE).isFalse();
}
@Test
void treeWithComments() {
var op = new CheckstyleOperation().fromProject(new Project()).treeWithComments(true);
- assertThat(op.options.containsKey("-T")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-T")).as(ADD).isTrue();
op = op.treeWithComments(false);
- assertThat(op.options.containsKey("-T")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-T")).as(REMOVE).isFalse();
}
@Test
void treeWithJavadoc() {
var op = new CheckstyleOperation().fromProject(new Project()).treeWithJavadoc(true);
- assertThat(op.options.containsKey("-J")).as(ADD).isTrue();
+ assertThat(op.options().containsKey("-J")).as(ADD).isTrue();
op = op.treeWithJavadoc(false);
- assertThat(op.options.containsKey("-J")).as(REMOVE).isFalse();
+ assertThat(op.options().containsKey("-J")).as(REMOVE).isFalse();
}
}
diff --git a/src/test/resources/checkstyle-args.txt b/src/test/resources/checkstyle-args.txt
new file mode 100644
index 0000000..fa76eaf
--- /dev/null
+++ b/src/test/resources/checkstyle-args.txt
@@ -0,0 +1,16 @@
+-b
+-c
+-d
+-e
+-E
+-f
+-g
+-j
+-J
+-o
+-p
+-s
+-t
+-T
+-w
+-x