From 43eabcb5b6b1b0a24071d67951ee0ab2e90c7408 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Tue, 18 Nov 2025 14:28:54 -0800 Subject: [PATCH 1/9] Allow for modulePath and classPath specification using a File array or collection --- .../operations/AbstractProcessOperation.java | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/main/java/rife/bld/operations/AbstractProcessOperation.java b/src/main/java/rife/bld/operations/AbstractProcessOperation.java index da47897..ef8a9a6 100644 --- a/src/main/java/rife/bld/operations/AbstractProcessOperation.java +++ b/src/main/java/rife/bld/operations/AbstractProcessOperation.java @@ -10,10 +10,7 @@ import rife.bld.operations.exceptions.OperationOptionException; import rife.tools.exceptions.FileUtilsErrorException; import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Function; /** @@ -233,6 +230,18 @@ public abstract class AbstractProcessOperation @@ -247,6 +256,20 @@ public abstract class AbstractProcessOperation + * A copy will be created to allow this list to be independently modifiable. + * + * @param classpath a list of classpath entries for the operation + * @return this operation instance + * @since 2.3.1 + */ + public T classpath(Collection classpath) { + classpath_.addAll(classpath.stream().map(File::getAbsolutePath).toList()); + return (T) this; + } + /** * Provides module path entries to use for the operation. * @@ -259,6 +282,17 @@ public abstract class AbstractProcessOperation @@ -273,6 +307,20 @@ public abstract class AbstractProcessOperation + * A copy will be created to allow this list to be independently modifiable. + * + * @param modulePath a list of module path entries for the operation + * @return this operation instance + * @since 2.3.1 + */ + public T modulePath(Collection modulePath) { + modulePath_.addAll(modulePath.stream().map(File::getAbsolutePath).toList()); + return (T) this; + } + /** * Provides the main class to launch with the java tool. * From 20845e4fcb1415b260e8b013d7545584dfd71ebc Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 27 Dec 2025 12:06:12 -0800 Subject: [PATCH 2/9] Add support for `--source` and `--target` in JavacOptions --- .../rife/bld/operations/JavacOptions.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index 4c6c208..d8b5061 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -253,6 +253,30 @@ public class JavacOptions extends ArrayList { return this; } + /** + * Provide source compatibility with the specified Java SE release. + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions source(int version) { + add("--source"); + add(Convert.toString(version)); + return this; + } + + /** + * Generate class files suitable for the specified Java SE release. + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions target(int version) { + add("--target"); + add(Convert.toString(version)); + return this; + } + /** * Generate debugging info * From db2adfaf7fd1fd8ec5ff5da7394dd5f78eb7fd4d Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 27 Dec 2025 12:22:27 -0800 Subject: [PATCH 3/9] Add support for `--add-exports` in JavacOptions --- .../rife/bld/operations/JavacOptions.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index d8b5061..bbe9c90 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -46,6 +46,32 @@ public class JavacOptions extends ArrayList { return this; } + /** + * Specifies a package to be considered as exported from its defining + * module to additional modules or to all unnamed modules when the value + * of other-module is ALL-UNNAMED. + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions addExports(String... modules) { + return addExports(Arrays.asList(modules)); + } + + /** + * Specifies a package to be considered as exported from its defining + * module to additional modules or to all unnamed modules when the value + * of other-module is ALL-UNNAMED. + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions addExports(List modules) { + add("--add-exports"); + add(StringUtils.join(modules, ",")); + return this; + } + /** * Root modules to resolve in addition to the initial modules, * or all modules on the module path if a module is From e1765804e0893b24f031fa46759d30eb14af9282 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 27 Dec 2025 18:39:05 -0800 Subject: [PATCH 4/9] Add support for `--add-reads`, `--default-module-for-created-files` and `--patch-module` in JavacOptions --- .../rife/bld/operations/JavacOptions.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index bbe9c90..806a652 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -72,6 +72,30 @@ public class JavacOptions extends ArrayList { return this; } + /** + * Specifies additional modules to be considered as required by a given + * module + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions addReads(String... modules) { + return addReads(Arrays.asList(modules)); + } + + /** + * Specifies additional modules to be considered as required by a given + * module + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions addReads(List modules) { + add("--add-reads"); + add(StringUtils.join(modules, ",")); + return this; + } + /** * Root modules to resolve in addition to the initial modules, * or all modules on the module path if a module is @@ -110,6 +134,19 @@ public class JavacOptions extends ArrayList { return this; } + /** + * Fallback target module for files created by annotation processors, + * if none specified or inferred + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions defaultModuleForCreatedFiles(String module) { + add("--default-module-for-created-files"); + add(module); + return this; + } + /** * Output source locations where deprecated APIs are used * @@ -267,6 +304,18 @@ public class JavacOptions extends ArrayList { return contains("-release"); } + /** + * Overrides or augments a module with classes and resources in JAR files or directories + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions patchModule(String module) { + add("--patch-module"); + add(module); + return this; + } + /** * Compile for the specified Java SE release. * From 96831543b1edb00937a49f36f5f05fd5436c7215 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 27 Dec 2025 18:40:50 -0800 Subject: [PATCH 5/9] Fix `containsRelease` method to check for `--release` instead of `-release` in JavacOptions --- src/main/java/rife/bld/operations/JavacOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index 806a652..19613c6 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -301,7 +301,7 @@ public class JavacOptions extends ArrayList { * @since 1.5.18 */ public boolean containsRelease() { - return contains("-release"); + return contains("--release"); } /** From 6c389d242a9d23818024f2e28ed0b9e950eb483f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sat, 27 Dec 2025 18:41:48 -0800 Subject: [PATCH 6/9] Cleanup Javadocs --- .../rife/bld/operations/JavacOptions.java | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index 19613c6..2bc81d9 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -49,7 +49,7 @@ public class JavacOptions extends ArrayList { /** * Specifies a package to be considered as exported from its defining * module to additional modules or to all unnamed modules when the value - * of other-module is ALL-UNNAMED. + * of other-module is ALL-UNNAMED * * @return this list of options * @since 2.3.1 @@ -61,7 +61,7 @@ public class JavacOptions extends ArrayList { /** * Specifies a package to be considered as exported from its defining * module to additional modules or to all unnamed modules when the value - * of other-module is ALL-UNNAMED. + * of other-module is ALL-UNNAMED * * @return this list of options * @since 2.3.1 @@ -73,8 +73,7 @@ public class JavacOptions extends ArrayList { } /** - * Specifies additional modules to be considered as required by a given - * module + * Specifies additional modules to be considered as required by a given module * * @return this list of options * @since 2.3.1 @@ -84,8 +83,7 @@ public class JavacOptions extends ArrayList { } /** - * Specifies additional modules to be considered as required by a given - * module + * Specifies additional modules to be considered as required by a given module * * @return this list of options * @since 2.3.1 @@ -98,8 +96,7 @@ public class JavacOptions extends ArrayList { /** * Root modules to resolve in addition to the initial modules, - * or all modules on the module path if a module is - * ALL-MODULE-PATH. + * or all modules on the module path if a module is ALL-MODULE-PATH * * @return this list of options * @since 1.5.18 @@ -110,8 +107,7 @@ public class JavacOptions extends ArrayList { /** * Root modules to resolve in addition to the initial modules, - * or all modules on the module path if a module is - * ALL-MODULE-PATH. + * or all modules on the module path if a module is ALL-MODULE-PATH * * @return this list of options * @since 1.5.18 @@ -159,7 +155,7 @@ public class JavacOptions extends ArrayList { } /** - * Enable preview language features. To be used in conjunction with {@link #release}. + * Enable preview language features. To be used in conjunction with {@link #release} * * @return this list of options * @since 1.5.18 @@ -294,7 +290,7 @@ public class JavacOptions extends ArrayList { } /** - * Indicates whether the Java SE release was set. + * Indicates whether the Java SE release was set * * @return {@code true} if the release was set; or * {@code false} otherwise @@ -317,7 +313,7 @@ public class JavacOptions extends ArrayList { } /** - * Compile for the specified Java SE release. + * Compile for the specified Java SE release * * @return this list of options * @since 1.5.18 @@ -329,7 +325,7 @@ public class JavacOptions extends ArrayList { } /** - * Provide source compatibility with the specified Java SE release. + * Provide source compatibility with the specified Java SE release * * @return this list of options * @since 2.3.1 @@ -341,7 +337,7 @@ public class JavacOptions extends ArrayList { } /** - * Generate class files suitable for the specified Java SE release. + * Generate class files suitable for the specified Java SE release * * @return this list of options * @since 2.3.1 @@ -583,7 +579,7 @@ public class JavacOptions extends ArrayList { } /** - * Control whether annotation processing and/or compilation is done. + * Control whether annotation processing and/or compilation is done * * @return this list of options * @since 1.5.18 From 374bbc12522671689cc32a8734f660f31d92bfee Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 28 Dec 2025 00:49:19 -0800 Subject: [PATCH 7/9] Add support for `-Xlint` options in JavacOptions --- .../rife/bld/operations/JavacOptions.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/main/java/rife/bld/operations/JavacOptions.java b/src/main/java/rife/bld/operations/JavacOptions.java index 2bc81d9..8338fa2 100644 --- a/src/main/java/rife/bld/operations/JavacOptions.java +++ b/src/main/java/rife/bld/operations/JavacOptions.java @@ -35,6 +35,49 @@ public class JavacOptions extends ArrayList { FULL, NONE, ONLY } + public enum XLintKey { + ALL, + AUXILIARYCLASS, + CAST, + CLASSFILE, + DANGLING_DOC_COMMENTS, + DEP_ANN, + DEPRECATION, + DIVZERO, + EMPTY, + EXPORTS, + FALLTHROUGH, + FINALLY, + IDENTITY, + INCUBATING, + LOSSY_CONVERSIONS, + MISSING_EXPLICIT_CTOR, + MODULE, + NONE, + OPENS, + OPTIONS, + OUTPUT_FILE_CLASH, + OVERLOADS, + OVERRIDES, + PATH, + PREVIEW, + PROCESSING, + RAWTYPES, + REMOVAL, + REQUIRES_AUTOMATIC, + REQUIRES_TRANSITIVE_AUTOMATIC, + RESTRICTED, + SERIAL, + STATIC, + STRICTFP, + SYNCHRONIZATION, + TEXT_BLOCKS, + THIS_ESCAPE, + TRY, + UNCHECKED, + VARARGS + } + /** * Option to pass to annotation processors * @@ -776,4 +819,56 @@ public class JavacOptions extends ArrayList { add("-Werror"); return this; } + + /** + * Enable recommended warning categories + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions xLint() { + add("-Xlint"); + return this; + } + + /** + * Warning categories to enable + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions xLint(XLintKey... keys) { + return xLint(Arrays.asList(keys)); + } + + /** + * Warning categories to enable + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions xLint(List keys) { + add("-Xlint:" + StringUtils.join(keys, ",").replaceAll("_", "-").toLowerCase()); + return this; + } + + /** + * Warning categories to disable + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions xLintDisable(XLintKey... keys) { + return xLintDisable(Arrays.asList(keys)); + } + /** + * Warning categories to disable + * + * @return this list of options + * @since 2.3.1 + */ + public JavacOptions xLintDisable(List keys) { + add("-Xlint:-" + StringUtils.join(keys, ",-").replaceAll("_", "-").toLowerCase()); + return this; + } } \ No newline at end of file From 1a1e97d0c414429e7ba9aeda24d76256fb5b0c6f Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 28 Dec 2025 00:57:18 -0800 Subject: [PATCH 8/9] Add unit tests for JavacOptions class --- .../rife/bld/operations/TestJavacOptions.java | 952 ++++++++++++++++++ 1 file changed, 952 insertions(+) create mode 100644 src/test/java/rife/bld/operations/TestJavacOptions.java diff --git a/src/test/java/rife/bld/operations/TestJavacOptions.java b/src/test/java/rife/bld/operations/TestJavacOptions.java new file mode 100644 index 0000000..59fc0a7 --- /dev/null +++ b/src/test/java/rife/bld/operations/TestJavacOptions.java @@ -0,0 +1,952 @@ +/* + * Copyright 2025 Erik C. Thauvin (https://erik.thauvin.net/) + * Licensed under the Apache License, Version 2.0 (the "License") + */ +package rife.bld.operations; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import rife.bld.operations.JavacOptions.XLintKey; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static rife.bld.operations.JavacOptions.XLintKey.*; + +/** + * Unit tests for JavacOptions class + */ +class TestJavacOptions { + private JavacOptions options; + + @BeforeEach + void setUp() { + options = new JavacOptions(); + } + + @Nested + class AddExportsTests { + @Test + void testAddExportsMethodChaining() { + options.addExports("mod1/pkg1=mod2") + .addExports("mod3/pkg3=ALL-UNNAMED") + .parameters(); + + assertEquals(5, options.size()); + assertTrue(options.contains("--add-exports")); + assertTrue(options.contains("-parameters")); + } + + @Test + void testAddExportsMultipleCalls() { + options.addExports("module1/package1=module2") + .addExports("module3/package3=ALL-UNNAMED"); + + assertEquals(4, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("module1/package1=module2", options.get(1)); + assertEquals("--add-exports", options.get(2)); + assertEquals("module3/package3=ALL-UNNAMED", options.get(3)); + } + + @Test + void testAddExportsReturnsThis() { + var result = options.addExports("module1/package1=module2"); + assertSame(options, result); + } + + @Test + void testAddExportsWithComplexModulePaths() { + options.addExports( + "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "jdk.compiler/com.sun.tools.javac.tree=mymodule" + ); + + assertEquals(2, options.size()); + assertTrue(options.get(1).contains("jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED")); + assertTrue(options.get(1).contains("jdk.compiler/com.sun.tools.javac.tree=mymodule")); + } + + @Test + void testAddExportsWithEmptyList() { + options.addExports(List.of()); + + assertEquals(2, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("", options.get(1)); + } + + @Test + void testAddExportsWithEmptyVarargs() { + options.addExports(); + + assertEquals(2, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("", options.get(1)); + } + + @Test + void testAddExportsWithList() { + var modules = Arrays.asList( + "mod1/pkg1=mod2", + "mod3/pkg3=ALL-UNNAMED", + "mod4/pkg4=mod5" + ); + options.addExports(modules); + + assertEquals(2, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("mod1/pkg1=mod2,mod3/pkg3=ALL-UNNAMED,mod4/pkg4=mod5", options.get(1)); + } + + @Test + void testAddExportsWithSingleModule() { + options.addExports("java.base/sun.security.util=ALL-UNNAMED"); + + assertEquals(2, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("java.base/sun.security.util=ALL-UNNAMED", options.get(1)); + } + + @Test + void testAddExportsWithVarargs() { + options.addExports("module1/package1=module2", "module3/package3=ALL-UNNAMED"); + + assertEquals(2, options.size()); + assertEquals("--add-exports", options.get(0)); + assertEquals("module1/package1=module2,module3/package3=ALL-UNNAMED", options.get(1)); + } + } + + @Nested + class AddReadsTests { + @Test + void testAddReadsMethodChaining() { + options.addReads("mod1=mod2") + .addReads("mod3=mod4") + .deprecation(); + + assertEquals(5, options.size()); + assertTrue(options.contains("--add-reads")); + assertTrue(options.contains("-deprecation")); + } + + @Test + void testAddReadsMultipleCalls() { + options.addReads("module1=module2") + .addReads("module3=module4"); + + assertEquals(4, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("module1=module2", options.get(1)); + assertEquals("--add-reads", options.get(2)); + assertEquals("module3=module4", options.get(3)); + } + + @Test + void testAddReadsReturnsThis() { + var result = options.addReads("module1=module2"); + assertSame(options, result); + } + + @Test + void testAddReadsWithEmptyList() { + options.addReads(List.of()); + + assertEquals(2, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("", options.get(1)); + } + + @Test + void testAddReadsWithEmptyVarargs() { + options.addReads(); + + assertEquals(2, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("", options.get(1)); + } + + @Test + void testAddReadsWithList() { + List modules = Arrays.asList("mod1=mod2", "mod3=mod4", "mod5=mod6"); + options.addReads(modules); + + assertEquals(2, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("mod1=mod2,mod3=mod4,mod5=mod6", options.get(1)); + } + + @Test + void testAddReadsWithSingleModule() { + options.addReads("mymodule=java.base"); + + assertEquals(2, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("mymodule=java.base", options.get(1)); + } + + @Test + void testAddReadsWithVarargs() { + options.addReads("module1=module2", "module3=module4"); + + assertEquals(2, options.size()); + assertEquals("--add-reads", options.get(0)); + assertEquals("module1=module2,module3=module4", options.get(1)); + } + } + + @Nested + class CombinedModuleOptionsTests { + @Test + void testAddReadsAndAddExportsTogether() { + options.addReads("module1=module2") + .addExports("module3/package3=ALL-UNNAMED"); + + assertEquals(4, options.size()); + assertTrue(options.contains("--add-reads")); + assertTrue(options.contains("--add-exports")); + } + + @Test + void testAllModuleOptionsWithRelease() { + options.release(17) + .addReads("mod1=mod2") + .addExports("mod3/pkg3=ALL-UNNAMED") + .addModules("java.sql", "java.xml"); + + assertTrue(options.containsRelease()); + assertTrue(options.contains("--add-reads")); + assertTrue(options.contains("--add-exports")); + assertTrue(options.contains("--add-modules")); + } + + @Test + void testModuleOptionsMethodChaining() { + var result = options + .addReads("mod1=mod2") + .addExports("mod3/pkg3=mod4") + .release(11) + .deprecation(); + + assertSame(options, result); + assertEquals(7, options.size()); + } + } + + @Nested + class DefaultModuleForCreatedFilesTests { + @Test + void testDefaultModuleForCreatedFilesMethodChaining() { + options.defaultModuleForCreatedFiles("mymodule") + .parameters() + .deprecation(); + + assertEquals(4, options.size()); + assertTrue(options.contains("--default-module-for-created-files")); + assertTrue(options.contains("-parameters")); + assertTrue(options.contains("-deprecation")); + } + + @Test + void testDefaultModuleForCreatedFilesReturnsThis() { + var result = options.defaultModuleForCreatedFiles("mymodule"); + assertSame(options, result); + } + + @Test + void testDefaultModuleForCreatedFilesWithAnnotationProcessing() { + options.defaultModuleForCreatedFiles("annotations.generated") + .sourceOutput("generated/sources") + .processorPath("lib/processors.jar"); + + assertEquals(6, options.size()); + assertTrue(options.contains("--default-module-for-created-files")); + assertTrue(options.contains("-s")); + assertTrue(options.contains("--processor-path")); + } + + @Test + void testDefaultModuleForCreatedFilesWithModulePath() { + options.defaultModuleForCreatedFiles("mymodule") + .modulePath("lib/modules") + .release(17); + + assertEquals(6, options.size()); + assertTrue(options.contains("--default-module-for-created-files")); + assertTrue(options.contains("--module-path")); + assertTrue(options.containsRelease()); + } + + @Test + void testDefaultModuleForCreatedFilesWithProcessing() { + options.defaultModuleForCreatedFiles("mymodule") + .process(JavacOptions.Processing.ONLY) + .processors("com.example.MyProcessor"); + + assertEquals(5, options.size()); + assertTrue(options.contains("--default-module-for-created-files")); + assertTrue(options.contains("-proc:only")); + assertTrue(options.contains("-processor")); + } + + @Test + void testDefaultModuleForCreatedFilesWithQualifiedName() { + options.defaultModuleForCreatedFiles("com.example.mymodule"); + + assertEquals(2, options.size()); + assertEquals("--default-module-for-created-files", options.get(0)); + assertEquals("com.example.mymodule", options.get(1)); + } + + @Test + void testDefaultModuleForCreatedFilesWithSingleModule() { + options.defaultModuleForCreatedFiles("mymodule"); + + assertEquals(2, options.size()); + assertEquals("--default-module-for-created-files", options.get(0)); + assertEquals("mymodule", options.get(1)); + } + + @Test + void testMultipleDefaultModuleForCreatedFilesCalls() { + options.defaultModuleForCreatedFiles("module1") + .defaultModuleForCreatedFiles("module2"); + + assertEquals(4, options.size()); + assertEquals("--default-module-for-created-files", options.get(0)); + assertEquals("module1", options.get(1)); + assertEquals("--default-module-for-created-files", options.get(2)); + assertEquals("module2", options.get(3)); + } + } + + @Nested + class PatchModuleTests { + @Test + void testMultiplePatchModuleCalls() { + options.patchModule("module1=path1") + .patchModule("module2=path2"); + + assertEquals(4, options.size()); + assertEquals("--patch-module", options.get(0)); + assertEquals("module1=path1", options.get(1)); + assertEquals("--patch-module", options.get(2)); + assertEquals("module2=path2", options.get(3)); + } + + @Test + void testPatchModuleMethodChaining() { + options.patchModule("module1=path1") + .patchModule("module2=path2") + .deprecation(); + + assertEquals(5, options.size()); + assertTrue(options.contains("--patch-module")); + assertTrue(options.contains("-deprecation")); + } + + @Test + void testPatchModuleReturnsThis() { + var result = options.patchModule("mymodule=path/to/classes"); + assertSame(options, result); + } + + @Test + void testPatchModuleWithDirectoryPath() { + options.patchModule("com.example.module=build/classes"); + + assertEquals(2, options.size()); + assertEquals("--patch-module", options.get(0)); + assertEquals("com.example.module=build/classes", options.get(1)); + } + + @Test + void testPatchModuleWithJarPath() { + options.patchModule("java.base=mylib.jar"); + + assertEquals(2, options.size()); + assertEquals("--patch-module", options.get(0)); + assertEquals("java.base=mylib.jar", options.get(1)); + } + + @Test + void testPatchModuleWithMultiplePaths() { + options.patchModule("mymodule=path1:path2:path3"); + + assertEquals(2, options.size()); + assertEquals("--patch-module", options.get(0)); + assertEquals("mymodule=path1:path2:path3", options.get(1)); + } + + @Test + void testPatchModuleWithOtherModuleOptions() { + options.patchModule("mymodule=classes") + .addModules("java.sql") + .release(17); + + assertEquals(6, options.size()); + assertTrue(options.contains("--patch-module")); + assertTrue(options.contains("--add-modules")); + assertTrue(options.containsRelease()); + } + + @Test + void testPatchModuleWithSingleModule() { + options.patchModule("mymodule=path/to/classes"); + + assertEquals(2, options.size()); + assertEquals("--patch-module", options.get(0)); + assertEquals("mymodule=path/to/classes", options.get(1)); + } + } + + @Nested + class ReleaseTests { + @Test + void testContainsReleaseAfterClear() { + options.release(11); + assertTrue(options.containsRelease()); + + options.clear(); + assertFalse(options.containsRelease()); + } + + @Test + void testContainsReleaseAfterMultipleOptions() { + options.deprecation() + .parameters() + .release(17) + .warningError(); + + assertTrue(options.containsRelease()); + } + + @Test + void testContainsReleaseWhenNotSet() { + assertFalse(options.containsRelease()); + } + + @Test + void testContainsReleaseWhenSet() { + options.release(11); + assertTrue(options.containsRelease()); + } + + @Test + void testContainsReleaseWithOnlyReleaseOption() { + options.add("--release"); + assertTrue(options.containsRelease()); + } + + @Test + void testContainsReleaseWithOtherOptions() { + options.deprecation() + .parameters() + .warningError(); + + assertFalse(options.containsRelease()); + } + + @Test + void testMultipleReleaseCalls() { + options.release(11) + .release(17); + + assertEquals(4, options.size()); + assertEquals("--release", options.get(0)); + assertEquals("11", options.get(1)); + assertEquals("--release", options.get(2)); + assertEquals("17", options.get(3)); + assertTrue(options.containsRelease()); + } + + @Test + void testReleaseMethodChaining() { + options.release(17) + .enablePreview() + .deprecation(); + + assertEquals(4, options.size()); + assertTrue(options.contains("--release")); + assertTrue(options.contains("--enable-preview")); + assertTrue(options.contains("-deprecation")); + } + + @Test + void testReleaseReturnsThis() { + var result = options.release(11); + assertSame(options, result); + } + + @Test + void testReleaseWithEnablePreview() { + options.release(21) + .enablePreview(); + + assertTrue(options.containsRelease()); + assertTrue(options.contains("--enable-preview")); + assertEquals(3, options.size()); + } + + @Test + void testReleaseWithVersion11() { + options.release(11); + + assertEquals(2, options.size()); + assertEquals("--release", options.get(0)); + assertEquals("11", options.get(1)); + } + + @Test + void testReleaseWithVersion17() { + options.release(17); + + assertEquals(2, options.size()); + assertEquals("--release", options.get(0)); + assertEquals("17", options.get(1)); + } + + @Test + void testReleaseWithVersion21() { + options.release(21); + + assertEquals(2, options.size()); + assertEquals("--release", options.get(0)); + assertEquals("21", options.get(1)); + } + + @Test + void testReleaseWithVersion8() { + options.release(8); + + assertEquals(2, options.size()); + assertEquals("--release", options.get(0)); + assertEquals("8", options.get(1)); + } + } + + @Nested + class SourceTests { + @Test + void testMultipleSourceCalls() { + options.source(11) + .source(17); + + assertEquals(4, options.size()); + assertEquals("--source", options.get(0)); + assertEquals("11", options.get(1)); + assertEquals("--source", options.get(2)); + assertEquals("17", options.get(3)); + } + + @Test + void testSourceMethodChaining() { + options.source(17) + .deprecation() + .parameters(); + + assertEquals(4, options.size()); + assertTrue(options.contains("--source")); + assertTrue(options.contains("-deprecation")); + assertTrue(options.contains("-parameters")); + } + + @Test + void testSourceReturnsThis() { + var result = options.source(11); + assertSame(options, result); + } + + @Test + void testSourceWithTarget() { + options.source(11) + .target(11); + + assertEquals(4, options.size()); + assertTrue(options.contains("--source")); + assertTrue(options.contains("--target")); + } + + @Test + void testSourceWithVersion11() { + options.source(11); + + assertEquals(2, options.size()); + assertEquals("--source", options.get(0)); + assertEquals("11", options.get(1)); + } + + @Test + void testSourceWithVersion17() { + options.source(17); + + assertEquals(2, options.size()); + assertEquals("--source", options.get(0)); + assertEquals("17", options.get(1)); + } + + @Test + void testSourceWithVersion21() { + options.source(21); + + assertEquals(2, options.size()); + assertEquals("--source", options.get(0)); + assertEquals("21", options.get(1)); + } + + @Test + void testSourceWithVersion8() { + options.source(8); + + assertEquals(2, options.size()); + assertEquals("--source", options.get(0)); + assertEquals("8", options.get(1)); + } + } + + @Nested + class TargetTests { + @Test + void testMultipleTargetCalls() { + options.target(11) + .target(17); + + assertEquals(4, options.size()); + assertEquals("--target", options.get(0)); + assertEquals("11", options.get(1)); + assertEquals("--target", options.get(2)); + assertEquals("17", options.get(3)); + } + + @Test + void testTargetMethodChaining() { + options.target(17) + .deprecation() + .parameters(); + + assertEquals(4, options.size()); + assertTrue(options.contains("--target")); + assertTrue(options.contains("-deprecation")); + assertTrue(options.contains("-parameters")); + } + + @Test + void testTargetReturnsThis() { + var result = options.target(11); + assertSame(options, result); + } + + @Test + void testTargetWithRelease() { + options.target(17) + .release(17) + .enablePreview(); + + assertEquals(5, options.size()); + assertTrue(options.contains("--target")); + assertTrue(options.contains("--release")); + assertTrue(options.contains("--enable-preview")); + } + + @Test + void testTargetWithSource() { + options.target(17) + .source(17); + + assertEquals(4, options.size()); + assertTrue(options.contains("--target")); + assertTrue(options.contains("--source")); + } + + @Test + void testTargetWithVersion11() { + options.target(11); + + assertEquals(2, options.size()); + assertEquals("--target", options.get(0)); + assertEquals("11", options.get(1)); + } + + @Test + void testTargetWithVersion17() { + options.target(17); + + assertEquals(2, options.size()); + assertEquals("--target", options.get(0)); + assertEquals("17", options.get(1)); + } + + @Test + void testTargetWithVersion21() { + options.target(21); + + assertEquals(2, options.size()); + assertEquals("--target", options.get(0)); + assertEquals("21", options.get(1)); + } + + @Test + void testTargetWithVersion8() { + options.target(8); + + assertEquals(2, options.size()); + assertEquals("--target", options.get(0)); + assertEquals("8", options.get(1)); + } + } + + @Nested + class XLintTests { + @Test + void testMultipleXLintCalls() { + options.xLint(DEPRECATION) + .xLint(UNCHECKED); + + assertEquals(2, options.size()); + assertTrue(options.contains("-Xlint:deprecation")); + assertTrue(options.contains("-Xlint:unchecked")); + } + + @Test + void testMultipleXLintDisableCalls() { + options.xLintDisable(RAWTYPES) + .xLintDisable(SERIAL); + + assertEquals(2, options.size()); + assertTrue(options.contains("-Xlint:-rawtypes")); + assertTrue(options.contains("-Xlint:-serial")); + } + + @Test + void testXLintAllKey() { + options.xLint(ALL); + + assertTrue(options.contains("-Xlint:all")); + } + + @Test + void testXLintBasic() { + options.xLint(); + + assertTrue(options.contains("-Xlint")); + assertEquals(1, options.size()); + } + + @Test + void testXLintCaseSensitivity() { + options.xLint(DEPRECATION, UNCHECKED); + + var result = options.get(0); + assertEquals("-Xlint:deprecation,unchecked", result); + assertFalse(result.contains("DEPRECATION")); + assertFalse(result.contains("UNCHECKED")); + } + + @Test + void testXLintCombinedWithOtherOptions() { + options.deprecation() + .xLint(UNCHECKED, RAWTYPES) + .warningError(); + + assertEquals(3, options.size()); + assertTrue(options.contains("-deprecation")); + assertTrue(options.contains("-Xlint:unchecked,rawtypes")); + assertTrue(options.contains("-Werror")); + } + + @Test + void testXLintDisableAllKey() { + options.xLintDisable(ALL); + + assertTrue(options.contains("-Xlint:-all")); + } + + @Test + void testXLintDisableCombinedWithOtherOptions() { + options.xLint() + .xLintDisable(DEPRECATION) + .parameters(); + + assertEquals(3, options.size()); + assertTrue(options.contains("-Xlint")); + assertTrue(options.contains("-Xlint:-deprecation")); + assertTrue(options.contains("-parameters")); + } + + @Test + void testXLintDisableEmptyList() { + List emptyList = List.of(); + options.xLintDisable(emptyList); + + assertEquals(1, options.size()); + assertEquals("-Xlint:-", options.get(0)); + } + + @Test + void testXLintDisableReturnsThis() { + var result = options.xLintDisable(UNCHECKED); + assertSame(options, result); + } + + @Test + void testXLintDisableWithList() { + var keys = Arrays.asList(SERIAL, STATIC, STRICTFP); + options.xLintDisable(keys); + + assertTrue(options.contains("-Xlint:-serial,-static,-strictfp")); + assertEquals(1, options.size()); + } + + @Test + void testXLintDisableWithMultipleKeys() { + options.xLintDisable(UNCHECKED, RAWTYPES, FALLTHROUGH); + + assertTrue(options.contains("-Xlint:-unchecked,-rawtypes,-fallthrough")); + assertEquals(1, options.size()); + } + + @Test + void testXLintDisableWithSingleKey() { + options.xLintDisable(DEPRECATION); + + assertTrue(options.contains("-Xlint:-deprecation")); + assertEquals(1, options.size()); + } + + @Test + void testXLintDisableWithUnderscoreConversion() { + options.xLintDisable(DEP_ANN, MISSING_EXPLICIT_CTOR); + + assertTrue(options.contains("-Xlint:-dep-ann,-missing-explicit-ctor")); + assertEquals(1, options.size()); + } + + @Test + void testXLintEmptyList() { + List emptyList = List.of(); + options.xLint(emptyList); + + assertEquals(1, options.size()); + assertEquals("-Xlint:", options.get(0)); + } + + @Test + void testXLintMethodChaining() { + var result = options + .xLint() + .xLint(DEPRECATION) + .xLintDisable(RAWTYPES) + .deprecation(); + + assertSame(options, result); + assertEquals(4, options.size()); + } + + @Test + void testXLintNoneKey() { + options.xLint(NONE); + + assertTrue(options.contains("-Xlint:none")); + } + + @Test + void testXLintReturnsThis() { + var result = options.xLint(); + assertSame(options, result); + } + + @Test + void testXLintWithAllAvailableKeys() { + options.xLint( + ALL, AUXILIARYCLASS, CAST, CLASSFILE, DANGLING_DOC_COMMENTS, + DEP_ANN, DEPRECATION, DIVZERO, EMPTY, EXPORTS, FALLTHROUGH, + FINALLY, IDENTITY, INCUBATING, LOSSY_CONVERSIONS, + MISSING_EXPLICIT_CTOR, MODULE, NONE, OPENS, OPTIONS, + OUTPUT_FILE_CLASH, OVERLOADS, OVERRIDES, PATH, PREVIEW, + PROCESSING, RAWTYPES, REMOVAL, REQUIRES_AUTOMATIC, + REQUIRES_TRANSITIVE_AUTOMATIC, RESTRICTED, SERIAL, STATIC, + STRICTFP, SYNCHRONIZATION, TEXT_BLOCKS, THIS_ESCAPE, + TRY, UNCHECKED, VARARGS + ); + + String[] keys = { + "all", "auxiliaryclass", "cast", "classfile", "dangling-doc-comments", + "dep-ann", "deprecation", "divzero", "empty", "exports", "fallthrough", + "finally", "identity", "incubating", "lossy-conversions", + "missing-explicit-ctor", "module", "none", "opens", "options", + "output-file-clash", "overloads", "overrides", "path", "preview", + "processing", "rawtypes", "removal", "requires-automatic", + "requires-transitive-automatic", "restricted", "serial", "static", + "strictfp", "synchronization", "text-blocks", "this-escape", + "try", "unchecked", "varargs" + }; + + assertEquals(1, options.size()); + var result = options.get(0); + assertTrue(result.startsWith("-Xlint:")); + + for (var key : keys) { + assertTrue(result.contains(key)); + } + } + + @Test + void testXLintWithAllUnderscoreKeys() { + options.xLint( + DANGLING_DOC_COMMENTS, + LOSSY_CONVERSIONS, + REQUIRES_AUTOMATIC, + REQUIRES_TRANSITIVE_AUTOMATIC, + TEXT_BLOCKS, + THIS_ESCAPE + ); + + var expected = "-Xlint:dangling-doc-comments,lossy-conversions,requires-automatic," + + "requires-transitive-automatic,text-blocks,this-escape"; + assertTrue(options.contains(expected)); + assertEquals(1, options.size()); + } + + @Test + void testXLintWithKeysReturnsThis() { + var result = options.xLint(DEPRECATION); + assertSame(options, result); + } + + @Test + void testXLintWithList() { + var keys = Arrays.asList(CAST, DIVZERO, EMPTY); + options.xLint(keys); + + assertTrue(options.contains("-Xlint:cast,divzero,empty")); + assertEquals(1, options.size()); + } + + @Test + void testXLintWithMultipleKeys() { + options.xLint(DEPRECATION, UNCHECKED, RAWTYPES); + + assertTrue(options.contains("-Xlint:deprecation,unchecked,rawtypes")); + assertEquals(1, options.size()); + } + + @Test + void testXLintWithSingleKey() { + options.xLint(ALL); + + assertTrue(options.contains("-Xlint:all")); + assertEquals(1, options.size()); + } + + @Test + void testXLintWithUnderscoreConversion() { + options.xLint(DEP_ANN, OUTPUT_FILE_CLASH, MISSING_EXPLICIT_CTOR); + + assertTrue(options.contains("-Xlint:dep-ann,output-file-clash,missing-explicit-ctor")); + assertEquals(1, options.size()); + } + } +} From 44bce493ac493348e4b9869b6655d1591984c192 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 28 Dec 2025 01:12:08 -0800 Subject: [PATCH 9/9] Add JUnit reporter integration and update workflow steps --- .github/workflows/bld.yml | 45 +++++++++++++++++++++++++++++---- lib/bld/bld-wrapper.properties | 1 + src/bld/java/rife/BldBuild.java | 9 +++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/.github/workflows/bld.yml b/.github/workflows/bld.yml index 1446b0a..66a1cc5 100644 --- a/.github/workflows/bld.yml +++ b/.github/workflows/bld.yml @@ -2,6 +2,9 @@ name: bld-ci on: [push, pull_request, workflow_dispatch] +env: + REPORTS_DIR: "build/test-results/test/" + jobs: build-linux: runs-on: ubuntu-latest @@ -104,12 +107,24 @@ jobs: java-version: ${{ matrix.java-version }} check-latest: true + - name: Download dependencies + run: ./bld clean download + + - name: Compile source + run: ./bld compile + - name: Run tests + id: tests run: >- - ./bld clean download compile test + ./bld test -Dtest.postgres=true -Dtest.mysql=true -Dtest.mariadb=true -Dtest.oracle=true -Dtest.oracle-free=true -DtestsBadgeUrl=https://rife2.com/tests-badge/update/com.uwyn.rife2/bld -DtestsBadgeApiKey=${{ secrets.TESTS_BADGE_API_KEY }} + --reports-dir=${{ env.REPORTS_DIR }} + + - name: Run reporter + if: always() && steps.tests.outcome == 'failure' + run: ./bld reporter --all build-macos: runs-on: macos-latest @@ -133,9 +148,19 @@ jobs: java-version: ${{ matrix.java-version }} check-latest: true + - name: Download dependencies + run: ./bld clean download + + - name: Compile source + run: ./bld compile + - name: Run tests - run: >- - ./bld clean download compile test + id: tests + run: ./bld test --reports-dir=${{ env.REPORTS_DIR }} + + - name: Run reporter + if: always() && steps.tests.outcome == 'failure' + run: ./bld reporter --all build-windows: runs-on: windows-latest @@ -162,6 +187,16 @@ jobs: java-version: ${{ matrix.java-version }} check-latest: true + - name: Download dependencies + run: .\bld.bat clean download + + - name: Compile source + run: .\bld.bat compile + - name: Run tests - run: >- - .\bld.bat clean download compile test + id: tests + run: .\bld.bat test --reports-dir=${{ env.REPORTS_DIR }} + + - name: Run reporter + if: always() && steps.tests.outcome == 'failure' + run: .\bld.bat reporter --all diff --git a/lib/bld/bld-wrapper.properties b/lib/bld/bld-wrapper.properties index 21bd7dd..3d1879e 100644 --- a/lib/bld/bld-wrapper.properties +++ b/lib/bld/bld-wrapper.properties @@ -3,6 +3,7 @@ bld.downloadExtensionSources=true bld.downloadLocation= bld.extension-antlr=com.uwyn.rife2:bld-antlr4:1.4.3 bld.extension-archive=com.uwyn.rife2:bld-archive:0.6.3 +bld.extension-reporter=com.uwyn.rife2:bld-junit-reporter:0.9.2 bld.extension-tests=com.uwyn.rife2:bld-tests-badge:1.6.3 bld.javaOptions= bld.javacOptions= diff --git a/src/bld/java/rife/BldBuild.java b/src/bld/java/rife/BldBuild.java index 538ae68..d3875e7 100644 --- a/src/bld/java/rife/BldBuild.java +++ b/src/bld/java/rife/BldBuild.java @@ -7,6 +7,7 @@ package rife; import rife.bld.BuildCommand; import rife.bld.Cli; import rife.bld.dependencies.VersionNumber; +import rife.bld.extension.JUnitReporterOperation; import rife.bld.extension.ZipOperation; import rife.bld.operations.*; import rife.bld.publish.*; @@ -161,6 +162,14 @@ public class BldBuild extends AbstractRife2Build { zipBld(); } + @BuildCommand(summary = "Runs the JUnit reporter") + public void reporter() throws Exception { + new JUnitReporterOperation() + .fromProject(this) + .failOnSummary(true) + .execute(); + } + public void publish() throws Exception { all();