files) {
+ return argFile(files.stream().map(File::new).toList());
+ }
+
/**
* Returns the formatted arguments.
*
@@ -198,13 +255,27 @@ public class CompileOptions {
// @argfile
if (!argFile_.isEmpty()) {
- argFile_.forEach(f -> args.add("@" + f.getAbsolutePath()));
- }
-
- // classpath
- if (!classpath_.isEmpty()) {
- args.add("-classpath");
- args.add(classpath_.stream().map(File::getAbsolutePath).collect(Collectors.joining(File.pathSeparator)));
+ argFile_.forEach(f -> {
+ if (f.exists()) {
+ try {
+ try (var reader = Files.newBufferedReader(f.toPath(), Charset.defaultCharset())) {
+ var tokenizer = new AbstractToolProviderOperation.CommandLineTokenizer(reader);
+ String token;
+ while ((token = tokenizer.nextToken()) != null) {
+ args.add(token);
+ }
+ }
+ } catch (IOException e) {
+ if (LOGGER.isLoggable(Level.WARNING)) {
+ LOGGER.log(Level.WARNING, "Could not read: " + f.getAbsolutePath(), e);
+ }
+ }
+ } else {
+ if (LOGGER.isLoggable(Level.WARNING)) {
+ LOGGER.warning("File not found: " + f.getAbsolutePath());
+ }
+ }
+ });
}
// expression
@@ -240,11 +311,6 @@ public class CompileOptions {
args.add("-Xjdk-release=" + jdkRelease_);
}
- // JVM options
- if (!jvmOptions_.isEmpty()) {
- jvmOptions_.forEach(s -> args.add("-J" + s));
- }
-
// kotlin-home
if (kotlinHome_ != null) {
args.add("-kotlin-home");
@@ -327,9 +393,20 @@ public class CompileOptions {
args.add("-Werror");
}
- // advanced option (X)
+ // Wextra
+ if (wExtra_) {
+ args.add("-Wextra");
+ }
+
+ // advanced options (X)
if (!advancedOptions_.isEmpty()) {
- advancedOptions_.forEach(it -> args.add("-X" + it));
+ advancedOptions_.forEach(it -> {
+ if (it.startsWith("-X")) {
+ args.add(it);
+ } else {
+ args.add("-X" + it);
+ }
+ });
}
return args;
@@ -342,10 +419,10 @@ public class CompileOptions {
*
* @param paths one pr more paths
* @return this operation instance
+ * @see #classpathStrings(Collection)
*/
public CompileOptions classpath(String... paths) {
- classpath_.addAll(Arrays.stream(paths).map(File::new).toList());
- return this;
+ return classpathStrings(List.of(paths));
}
/**
@@ -355,10 +432,23 @@ public class CompileOptions {
*
* @param paths one or more path
* @return this operation instance
+ * @see #classpath(Collection)
*/
public CompileOptions classpath(File... paths) {
- classpath_.addAll(List.of(paths));
- return this;
+ return classpath(List.of(paths));
+ }
+
+ /**
+ * Search for class files in the specified paths.
+ *
+ * The classpath can contain file and directory paths, ZIP, or JAR files.
+ *
+ * @param paths one or more path
+ * @return this operation instance
+ * @see #classpathPaths(Collection)
+ */
+ public CompileOptions classpath(Path... paths) {
+ return classpathPaths(List.of(paths));
}
/**
@@ -368,6 +458,7 @@ public class CompileOptions {
*
* @param paths the search paths
* @return this operation instance
+ * @see #classpath(File...)
*/
public CompileOptions classpath(Collection paths) {
classpath_.addAll(paths);
@@ -383,6 +474,41 @@ public class CompileOptions {
return classpath_;
}
+ /**
+ * Search for class files in the specified paths.
+ *
+ * The classpath can contain file and directory paths, ZIP, or JAR files.
+ *
+ * @param paths one pr more paths
+ * @return this operation instance
+ * @see #classpath(Path...)
+ */
+ public CompileOptions classpathPaths(Collection paths) {
+ return classpath(paths.stream().map(Path::toFile).toList());
+ }
+
+ /**
+ * Search for class files in the specified paths.
+ *
+ * The classpath can contain file and directory paths, ZIP, or JAR files.
+ *
+ * @param paths one pr more paths
+ * @return this operation instance
+ * @see #classpath(String...)
+ */
+ public CompileOptions classpathStrings(Collection paths) {
+ return classpath(paths.stream().map(File::new).toList());
+ }
+
+ /**
+ * Retrieves the string to evaluate as a Kotlin script.
+ *
+ * @return the expression
+ */
+ public String expression() {
+ return expression_;
+ }
+
/**
* Evaluate the given string as a Kotlin script.
*
@@ -415,6 +541,69 @@ public class CompileOptions {
return this;
}
+ /**
+ * Indicates whether the {@link #includeRuntime(boolean)} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isIncludeRuntime() {
+ return includeRuntime_;
+ }
+
+ /**
+ * Indicates whether {@link #javaParameters(boolean)} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isJavaParameters() {
+ return javaParameters_;
+ }
+
+ /**
+ * Indicates whether {@link #noJdk(boolean) noJdk} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isNoJdk() {
+ return noJdk_;
+ }
+
+ /**
+ * Indicates whether {@link #noReflect(boolean) noRflect} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isNoReflect() {
+ return noReflect_;
+ }
+
+ /**
+ * Indicates whether {@link #noStdLib(boolean) noStdLib} +was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isNoStdLib() {
+ return noStdLib_;
+ }
+
+ /**
+ * Indicates whether {@link #noWarn(boolean) noWarn} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isNoWarn() {
+ return noWarn_;
+ }
+
+ /**
+ * Indicates whether {@link #progressive(boolean) progressive} was set.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isProgressive() {
+ return progressive_;
+ }
+
/**
* Indicates whether {@link #verbose(boolean)} was set.
*
@@ -424,6 +613,24 @@ public class CompileOptions {
return verbose_;
}
+ /**
+ * Indicates whether warnings are turned into a compilation error.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isWError() {
+ return wError_;
+ }
+
+ /**
+ * Indicates whether additional declaration, expression, and type compiler checks emit warnings.
+ *
+ * @return {@code true} or {@code false}
+ */
+ public boolean isWExtra() {
+ return wExtra_;
+ }
+
/**
* Generate metadata for Java 1.8 reflection on method parameters.
*
@@ -441,8 +648,8 @@ public class CompileOptions {
* @param jdkHome the JDK home path
* @return this operation instance
*/
- public CompileOptions jdkHome(String jdkHome) {
- jdkHome_ = new File(jdkHome);
+ public CompileOptions jdkHome(File jdkHome) {
+ jdkHome_ = jdkHome;
return this;
}
@@ -452,18 +659,45 @@ public class CompileOptions {
* @param jdkHome the JDK home path
* @return this operation instance
*/
- public CompileOptions jdkHome(File jdkHome) {
- jdkHome_ = jdkHome;
- return this;
+ public CompileOptions jdkHome(String jdkHome) {
+ return jdkHome(new File(jdkHome));
}
/**
- * Specify the target version of the generated JVM bytecode.
+ * Use a custom JDK home directory to include into the classpath if it differs from the default {@code JAVA_HOME}.
+ *
+ * @param jdkHome the JDK home path
+ * @return this operation instance
+ */
+ public CompileOptions jdkHome(Path jdkHome) {
+ return jdkHome(jdkHome.toFile());
+ }
+
+ /**
+ * Retrieves the custom JDK home directory.
+ *
+ * @return the JDK home path.
+ */
+ public File jdkHome() {
+ return jdkHome_;
+ }
+
+ /**
+ * Return the specified JDK API version.
+ *
+ * @return the API version
+ */
+ public String jdkRelease() {
+ return jdkRelease_;
+ }
+
+ /**
+ * Compile against the specified JDK API version.
*
* Limit the API of the JDK in the classpath to the specified Java version. Automatically sets
* {@link #jvmTarget(String) JVM target} version.
*
- * Possible values are 1.8, 9, 10, ..., 21. The default value is 1.8.
+ * Possible values are 1.8, 9, 10, ..., 23. The default value is 1.8.
*
* @param version the target version
* @return this operation instance
@@ -474,59 +708,17 @@ public class CompileOptions {
}
/**
- * Specify the target version of the generated JVM bytecode.
+ * Compile against the specified JDK API version.
+ *
+ * Limit the API of the JDK in the classpath to the specified Java version. Automatically sets
+ * {@link #jvmTarget(String) JVM target} version.
*
* @param version the target version
* @return this operation instance
* @see #jdkRelease(String)
*/
public CompileOptions jdkRelease(int version) {
- jdkRelease_ = String.valueOf(version);
- return this;
- }
-
- /**
- * Pass an option directly to JVM
- *
- * @param jvmOptions one or more JVM option
- * @return this operation instance
- */
- public CompileOptions jvmOptions(String... jvmOptions) {
- jvmOptions_.addAll(List.of(jvmOptions));
- return this;
- }
-
- /**
- * Retrieves the Java Virtual Machine options.
- *
- * @return the JVM options
- */
- public Collection jvmOptions() {
- return jvmOptions_;
- }
-
- /**
- * Pass an option directly to Java Virtual Machine
- *
- * @param jvmOptions the JVM options
- * @return this operation instance
- */
- public CompileOptions jvmOptions(Collection jvmOptions) {
- jvmOptions_.addAll(jvmOptions);
- return this;
- }
-
- /**
- * Specify the target version of the generated JVM bytecode.
- *
- * Possible values are 1.8, 9, 10, ..., 21. The default value is 1.8.
- *
- * @param target the target version
- * @return this operation instance
- */
- public CompileOptions jvmTarget(String target) {
- jvmTarget_ = target;
- return this;
+ return jdkRelease(String.valueOf(version));
}
/**
@@ -537,10 +729,31 @@ public class CompileOptions {
* @see #jvmTarget(String)
*/
public CompileOptions jvmTarget(int target) {
- jvmTarget_ = String.valueOf(target);
+ return jvmTarget(String.valueOf(target));
+ }
+
+ /**
+ * Specify the target version of the generated JVM bytecode.
+ *
+ * Possible values are 1.8, 9, 10, ..., 23. The default value is 1.8.
+ *
+ * @param target the target version
+ * @return this operation instance
+ */
+ public CompileOptions jvmTarget(String target) {
+ jvmTarget_ = target;
return this;
}
+ /**
+ * Retrieves the target version of the generated JVM bytecode.
+ *
+ * @return the target version
+ */
+ public String jvmTarget() {
+ return jvmTarget_;
+ }
+
/**
* Specify a custom path to the Kotlin compiler used for the discovery of runtime libraries.
*
@@ -552,6 +765,25 @@ public class CompileOptions {
return this;
}
+ /**
+ * Retrieves the custom path of the Kotlin compiler.
+ *
+ * @return the Kotlin home path
+ */
+ public File kotlinHome() {
+ return kotlinHome_;
+ }
+
+ /**
+ * Specify a custom path to the Kotlin compiler used for the discovery of runtime libraries.
+ *
+ * @param path the Kotlin home path
+ * @return this operation instance
+ */
+ public CompileOptions kotlinHome(Path path) {
+ return kotlinHome(path.toFile());
+ }
+
/**
* Specify a custom path to the Kotlin compiler used for the discovery of runtime libraries.
*
@@ -559,8 +791,7 @@ public class CompileOptions {
* @return this operation instance
*/
public CompileOptions kotlinHome(String path) {
- kotlinHome_ = new File(path);
- return this;
+ return kotlinHome(new File(path));
}
/**
@@ -574,6 +805,15 @@ public class CompileOptions {
return this;
}
+ /**
+ * Retrieves the {@link #languageVersion(String) language version}.
+ *
+ * @return the language version
+ */
+ public String languageVersion() {
+ return languageVersion_;
+ }
+
/**
* Set a custom name for the generated {@code .kotlin_module} file.
*
@@ -585,6 +825,15 @@ public class CompileOptions {
return this;
}
+ /**
+ * Retrieves the {@link #moduleName(String) module name}.
+ *
+ * @return the module name
+ */
+ public String moduleName() {
+ return moduleName_;
+ }
+
/**
* Don't automatically include the Java runtime into the classpath.
*
@@ -637,8 +886,7 @@ public class CompileOptions {
* @return this operation instance
*/
public CompileOptions optIn(String... annotations) {
- optIn_.addAll(List.of(annotations));
- return this;
+ return optIn(List.of(annotations));
}
/**
@@ -668,8 +916,7 @@ public class CompileOptions {
* @return this operation instance
*/
public CompileOptions options(String... options) {
- options_.addAll(List.of(options));
- return this;
+ return options(List.of(options));
}
/**
@@ -705,6 +952,27 @@ public class CompileOptions {
return this;
}
+ /**
+ * Retrieves the location to place generated class files into.
+ *
+ * @return the location path.
+ */
+ public File path() {
+ return path_;
+ }
+
+ /**
+ * Place the generated class files into the specified location.
+ *
+ * The location can be a directory, a ZIP, or a JAR file.
+ *
+ * @param path the location path
+ * @return this operation instance
+ */
+ public CompileOptions path(Path path) {
+ return path(path.toFile());
+ }
+
/**
* Place the generated class files into the specified location.
*
@@ -714,8 +982,7 @@ public class CompileOptions {
* @return this operation instance
*/
public CompileOptions path(String path) {
- path_ = new File(path);
- return this;
+ return path(new File(path));
}
/**
@@ -734,7 +1001,7 @@ public class CompileOptions {
/**
* Retrieves the plugin options.
*
- * @return the plugin ofoptions.
+ * @return the plugin options.
*/
public Collection plugin() {
return plugin_;
@@ -760,8 +1027,7 @@ public class CompileOptions {
* @return this operation instance
*/
public CompileOptions scriptTemplates(String... classNames) {
- scriptTemplates_.addAll(List.of(classNames));
- return this;
+ return scriptTemplates(List.of(classNames));
}
/**
@@ -807,4 +1073,15 @@ public class CompileOptions {
wError_ = wError;
return this;
}
+
+ /**
+ * Enable additional declaration, expression, and type compiler checks that emit warnings if {@code true}.
+ *
+ * @param wExtra {@code true} or {@code false}
+ * @return this operation instance
+ */
+ public CompileOptions wExtra(boolean wExtra) {
+ wExtra_ = wExtra;
+ return this;
+ }
}
diff --git a/src/main/java/rife/bld/extension/kotlin/CompilerPlugin.java b/src/main/java/rife/bld/extension/kotlin/CompilerPlugin.java
index bbf3304..f1fd584 100644
--- a/src/main/java/rife/bld/extension/kotlin/CompilerPlugin.java
+++ b/src/main/java/rife/bld/extension/kotlin/CompilerPlugin.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.
@@ -17,6 +17,7 @@
package rife.bld.extension.kotlin;
/**
+ * @author Erik C. Thauvin
* Defines the known Kotlin compiler plugin JARs.
*
* @author Erik C. Thauvin
@@ -25,6 +26,8 @@ package rife.bld.extension.kotlin;
public enum CompilerPlugin {
ALL_OPEN("allopen-compiler-plugin.jar"),
ASSIGNMENT("assignment-compiler-plugin.jar"),
+ COMPOSE("compose-compiler-plugin.jar"),
+ KOTLIN_IMPORTS_DUMPER("kotlin-imports-dumper-compiler-plugin.jar"),
KOTLINX_SERIALIZATION("kotlinx-serialization-compiler-plugin.jar"),
KOTLIN_SERIALIZATION("kotlin-serialization-compiler-plugin.jar"),
LOMBOK("lombok-compiler-plugin.jar"),
diff --git a/src/main/java/rife/bld/extension/kotlin/JvmOptions.java b/src/main/java/rife/bld/extension/kotlin/JvmOptions.java
new file mode 100644
index 0000000..7e2ec62
--- /dev/null
+++ b/src/main/java/rife/bld/extension/kotlin/JvmOptions.java
@@ -0,0 +1,90 @@
+/*
+ * 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.kotlin;
+
+import rife.tools.StringUtils;
+
+import java.io.Serial;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Java Virtual Machine options.
+ *
+ * @author Erik C. Thauvin
+ * @since 1.1.0
+ */
+@SuppressWarnings("PMD.LooseCoupling")
+public class JvmOptions extends ArrayList {
+ /**
+ * Keyword to enable native access for all code on the class path.
+ */
+ public final static String ALL_UNNAMED = "ALL-UNNAMED";
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Modules that are permitted to perform restricted native operations.
+ * The module name can also be {@link #ALL_UNNAMED}.
+ *
+ * @param modules the module names
+ * @return this list of options
+ */
+ public JvmOptions enableNativeAccess(String... modules) {
+ return enableNativeAccess(List.of(modules));
+ }
+
+ /**
+ * Modules that are permitted to perform restricted native operations.
+ * The module name can also be {@link #ALL_UNNAMED}.
+ *
+ * @param modules the module names
+ * @return this list of options
+ */
+ public JvmOptions enableNativeAccess(Collection modules) {
+ add("--enable-native-access=" + StringUtils.join(modules, ","));
+ return this;
+ }
+
+ /**
+ * Controls what action the Java runtime takes when native access is not enabled for a module.
+ *
+ * @param access the access mode
+ * @return this list of options
+ */
+ public JvmOptions illegalNativeAccess(NativeAccess access) {
+ add("--illegal-native-access=" + access.mode);
+ return this;
+ }
+
+ /**
+ * Illegal native access modes.
+ */
+ public enum NativeAccess {
+ ALLOW("allow"),
+ DENY("deny"),
+ WARN("warn");
+
+ public final String mode;
+
+ NativeAccess(String mode) {
+ this.mode = mode;
+ }
+ }
+}
diff --git a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java
index 231ff1e..4e0182e 100644
--- a/src/test/java/rife/bld/extension/CompileKotlinOperationTest.java
+++ b/src/test/java/rife/bld/extension/CompileKotlinOperationTest.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,13 +16,14 @@
package rife.bld.extension;
+import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import rife.bld.BaseProject;
-import rife.bld.Project;
import rife.bld.blueprints.BaseProjectBlueprint;
import rife.bld.extension.kotlin.CompileOptions;
import rife.bld.extension.kotlin.CompilerPlugin;
+import rife.bld.extension.kotlin.JvmOptions;
import rife.tools.FileUtils;
import java.io.File;
@@ -30,6 +31,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
@@ -37,7 +39,11 @@ import java.util.logging.Logger;
import static org.assertj.core.api.Assertions.assertThat;
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
class CompileKotlinOperationTest {
+ private static final String FILE_1 = "file1";
+ private static final String FILE_2 = "file2";
+
@BeforeAll
static void beforeAll() {
var level = Level.ALL;
@@ -49,10 +55,40 @@ class CompileKotlinOperationTest {
logger.setUseParentHandlers(false);
}
+ @Test
+ void testBuildMainDirectory() {
+ var foo = new File("foo");
+ var bar = new File("bar");
+
+ var op = new CompileKotlinOperation().buildMainDirectory(foo);
+ assertThat(op.buildMainDirectory()).as("as file").isEqualTo(foo);
+
+ op = op.buildMainDirectory(bar.toPath());
+ assertThat(op.buildMainDirectory()).as("as path").isEqualTo(bar);
+
+ op = new CompileKotlinOperation().buildMainDirectory("foo");
+ assertThat(op.buildMainDirectory()).as("as string").isEqualTo(foo);
+ }
+
+ @Test
+ void testBuildTestDirectory() {
+ var foo = new File("foo");
+ var bar = new File("bar");
+
+ var op = new CompileKotlinOperation().buildTestDirectory(foo);
+ assertThat(op.buildTestDirectory()).as("as file").isEqualTo(foo);
+
+ op = op.buildTestDirectory(bar.toPath());
+ assertThat(op.buildTestDirectory()).as("as path").isEqualTo(bar);
+
+ op = new CompileKotlinOperation().buildTestDirectory("foo");
+ assertThat(op.buildTestDirectory()).as("as string").isEqualTo(foo);
+ }
+
@Test
void testCollections() {
var op = new CompileKotlinOperation()
- .fromProject(new Project())
+ .fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", "Example", "Example"))
.kotlinHome("/kotlin_home")
.kotlinc("kotlinc")
.workDir("work_dir")
@@ -69,34 +105,45 @@ class CompileKotlinOperationTest {
.testSourceFiles(List.of(new File("tfile3"), new File("tfile4")))
.testSourceFiles(new File("tfile5"), new File("tfile6"))
.plugins("plugin1", "plugin2")
- .plugins(CompilerPlugin.KOTLIN_SERIALIZATION, CompilerPlugin.ASSIGNMENT)
+ .plugins(CompilerPlugin.KOTLIN_SERIALIZATION, CompilerPlugin.ASSIGNMENT, CompilerPlugin.COMPOSE)
.plugins(new File("lib/compile"), CompilerPlugin.LOMBOK, CompilerPlugin.POWER_ASSERT)
+ .plugins(Path.of("lib/compile"), CompilerPlugin.NOARG, CompilerPlugin.ALL_OPEN,
+ CompilerPlugin.KOTLIN_IMPORTS_DUMPER)
+ .plugins("lib/compile", CompilerPlugin.KOTLINX_SERIALIZATION, CompilerPlugin.SAM_WITH_RECEIVER)
.plugins(List.of("plugin3", "plugin4"));
- assertThat(op.kotlinHome().getName()).as("kotlin_home").isEqualTo("kotlin_home");
- assertThat(op.kotlinc().getName()).as("kotlinc").isEqualTo("kotlinc");
- assertThat(op.workDir().getName()).as("work_dir").isEqualTo("work_dir");
-
- assertThat(op.compileMainClasspath()).as("compileMainClassPath")
- .containsAll(List.of("path1", "path2"));
- assertThat(op.compileOptions().hasRelease()).as("hasRelease").isTrue();
- assertThat(op.compileOptions().isVerbose()).as("isVerbose").isTrue();
- assertThat(op.mainSourceDirectories()).as("mainSourceDirectories").containsExactly(
- Path.of("src", "main", "kotlin").toFile().getAbsoluteFile(), new File("dir1"),
- new File("dir2"), new File("dir3"), new File("dir4"));
- assertThat(op.testSourceDirectories()).as("testSourceDirectories").containsOnly(
- Path.of("src", "test", "kotlin").toFile().getAbsoluteFile(), new File("tdir1"),
- new File("tdir2"), new File("tdir3"), new File("tdir4"));
- assertThat(op.mainSourceFiles()).as("mainSourceFiles").containsOnly(
- new File("file1"), new File("file2"), new File("file3"),
- new File("file4"), new File("file5"), new File("file6"));
- assertThat(op.testSourceFiles()).as("testSourceFiles").containsOnly(
- new File("tfile1"), new File("tfile2"), new File("tfile3"),
- new File("tfile4"), new File("tfile5"), new File("tfile6"));
- assertThat(op.plugins()).as("plugins").contains("plugin2", "plugin3", "plugin4",
- "/kotlin_home/lib/kotlin-serialization-compiler-plugin.jar",
- "/kotlin_home/lib/assignment-compiler-plugin.jar");
- assertThat(op.plugins()).as("plugins size").hasSize(8);
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(op.kotlinHome().getName()).as("kotlin_home").isEqualTo("kotlin_home");
+ softly.assertThat(op.kotlinc().getName()).as("kotlinc").isEqualTo("kotlinc");
+ softly.assertThat(op.workDir().getName()).as("work_dir").isEqualTo("work_dir");
+ softly.assertThat(op.compileMainClasspath()).as("compileMainClassPath")
+ .containsAll(List.of("path1", "path2"));
+ softly.assertThat(op.compileOptions().hasRelease()).as("hasRelease").isTrue();
+ softly.assertThat(op.compileOptions().isVerbose()).as("isVerbose").isTrue();
+ softly.assertThat(op.mainSourceDirectories()).as("mainSourceDirectories").containsExactly(
+ Path.of("examples", "src", "main", "kotlin").toFile(), new File("dir1"),
+ new File("dir2"), new File("dir3"), new File("dir4"));
+ softly.assertThat(op.testSourceDirectories()).as("testSourceDirectories").containsOnly(
+ Path.of("examples", "src", "test", "kotlin").toFile(), new File("tdir1"),
+ new File("tdir2"), new File("tdir3"), new File("tdir4"));
+ softly.assertThat(op.mainSourceFiles()).as("mainSourceFiles").containsOnly(
+ new File("file1"), new File("file2"), new File("file3"),
+ new File("file4"), new File("file5"), new File("file6"));
+ softly.assertThat(op.testSourceFiles()).as("testSourceFiles").containsOnly(
+ new File("tfile1"), new File("tfile2"), new File("tfile3"),
+ new File("tfile4"), new File("tfile5"), new File("tfile6"));
+ softly.assertThat(op.plugins()).as("plugins").contains("plugin1", "plugin2", "plugin3", "plugin4",
+ new File("/kotlin_home/lib/kotlin-serialization-compiler-plugin.jar").getAbsolutePath(),
+ new File("/kotlin_home/lib/assignment-compiler-plugin.jar").getAbsolutePath(),
+ new File("/kotlin_home/lib/compose-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "lombok-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "power-assert-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "noarg-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "allopen-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "kotlin-imports-dumper-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "kotlinx-serialization-compiler-plugin.jar").getAbsolutePath(),
+ new File("lib/compile", "sam-with-receiver-compiler-plugin.jar").getAbsolutePath());
+ }
}
@Test
@@ -108,8 +155,10 @@ class CompileKotlinOperationTest {
var mainDir = new File(buildDir, "main");
var testDir = new File(buildDir, "test");
- assertThat(mainDir.mkdirs()).isTrue();
- assertThat(testDir.mkdirs()).isTrue();
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(mainDir.mkdirs()).as("make mainDir").isTrue();
+ softly.assertThat(testDir.mkdirs()).as("make testDir").isTrue();
+ }
var compileJars = new ArrayList();
for (var f : Objects.requireNonNull(new File("examples/lib/compile").listFiles())) {
@@ -122,8 +171,7 @@ class CompileKotlinOperationTest {
}
var op = new CompileKotlinOperation()
- .fromProject(new BaseProjectBlueprint(new File("examples"), "com.example",
- "Example"))
+ .fromProject(new BaseProjectBlueprint(new File("examples"), "com.example", "Example", "Example"))
.buildMainDirectory(mainDir)
.buildTestDirectory(testDir)
.compileMainClasspath(compileJars)
@@ -132,29 +180,171 @@ class CompileKotlinOperationTest {
.compileTestClasspath(mainDir.getAbsolutePath());
op.compileOptions().verbose(true);
- op.compileOptions().jdkRelease("17");
+ op.compileOptions().argFile("src/test/resources/argfile.txt", "src/test/resources/argfile2.txt");
+
+ if (!CompileKotlinOperation.isWindows()) {
+ op.jvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED);
+ assertThat(op.jvmOptions()).containsExactly("--enable-native-access=ALL-UNNAMED");
+ }
var args = op.compileOptions().args();
- var matches = List.of("-Xjdk-release=17", "-no-stdlib", "-verbose");
- assertThat(args).isEqualTo(matches);
+ var matches = List.of("-Xjdk-release=17", "-no-reflect", "-progressive", "-include-runtime", "-no-stdlib",
+ "-verbose");
+ assertThat(args).as(args + " == " + matches).isEqualTo(matches);
op.execute();
- assertThat(tmpDir).isNotEmptyDirectory();
- assertThat(mainDir).isNotEmptyDirectory();
- assertThat(testDir).isNotEmptyDirectory();
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(tmpDir).as("tmpDir").isNotEmptyDirectory();
+ softly.assertThat(mainDir).as("mainDir").isNotEmptyDirectory();
+ softly.assertThat(testDir).as("testDir").isNotEmptyDirectory();
+ }
var mainOut = Path.of(mainDir.getAbsolutePath(), "com", "example").toFile();
- assertThat(new File(mainOut, "Example.class")).exists();
- assertThat(new File(mainOut, "Example$Companion.class")).exists();
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(new File(mainOut, "Example.class")).as("Example.class").exists();
+ softly.assertThat(new File(mainOut, "Example$Companion.class"))
+ .as("ExampleCompanion.class").exists();
+ }
var testOut = Path.of(testDir.getAbsolutePath(), "com", "example").toFile();
- assertThat(new File(testOut, "ExampleTest.class")).exists();
+ assertThat(new File(testOut, "ExampleTest.class")).as("ExampleTest.class").exists();
} finally {
FileUtils.deleteDirectory(tmpDir);
}
}
+ @Test
+ void testFindKotlincPath() {
+ assertThat(CompileKotlinOperation.findKotlincPath()).doesNotStartWith("kotlinc");
+ }
+
+ @Test
+ void testFromProject() {
+ var examples = new File("examples");
+ var op = new CompileKotlinOperation().fromProject(
+ new BaseProjectBlueprint(examples, "com.example", "examples", "examples"));
+ assertThat(op.mainSourceDirectories()).containsExactly(new File(examples, "src/main/kotlin"));
+ assertThat(op.testSourceDirectories()).containsExactly(new File(examples, "src/test/kotlin"));
+ }
+
+ @Test
+ void testFromProjectNoKotlin() {
+ var op = new CompileKotlinOperation().fromProject(
+ new BaseProjectBlueprint(new File("foo"), "org.example", "foo", "foo"));
+ assertThat(op.mainSourceDirectories()).isEmpty();
+ assertThat(op.testSourceDirectories()).isEmpty();
+ }
+
+ @Test
+ void testIsOS() {
+ var osName = System.getProperty("os.name");
+ if (osName != null) {
+ var os = osName.toLowerCase(Locale.US);
+ if (os.contains("win")) {
+ assertThat(CompileKotlinOperation.isWindows()).isTrue();
+ } else if (os.contains("linux") || os.contains("unix")) {
+ assertThat(CompileKotlinOperation.isLinux()).isTrue();
+ } else if (os.contains("mac") || os.contains("darwin")) {
+ assertThat(CompileKotlinOperation.isMacOS()).isTrue();
+ }
+ }
+ }
+
+ @Test
+ void testKotlinHome() {
+ var foo = new File("foo");
+ var bar = new File("bar");
+
+ var op = new CompileKotlinOperation().kotlinHome(foo);
+ assertThat(op.kotlinHome()).as("as file").isEqualTo(foo);
+
+ op = op.kotlinHome(bar.toPath());
+ assertThat(op.kotlinHome()).as("as path").isEqualTo(bar);
+
+ op = new CompileKotlinOperation().kotlinHome("foo");
+ assertThat(op.kotlinHome()).as("as string").isEqualTo(foo);
+ }
+
+ @Test
+ void testKotlinc() {
+ var foo = new File("foo");
+ var bar = new File("bar");
+
+ var op = new CompileKotlinOperation().kotlinc(foo);
+ assertThat(op.kotlinc()).as("as file").isEqualTo(foo);
+
+ op = op.kotlinc(bar.toPath());
+ assertThat(op.kotlinc()).as("as path").isEqualTo(bar);
+
+ op = new CompileKotlinOperation().kotlinc("foo");
+ assertThat(op.kotlinc()).as("as string").isEqualTo(foo);
+ }
+
+ @Test
+ void testMainSourceDirectories() {
+ var op = new CompileKotlinOperation();
+
+ op.mainSourceDirectories(List.of(new File(FILE_1), new File(FILE_2)));
+ assertThat(op.mainSourceDirectories()).as("List(File...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+
+ op.mainSourceDirectories(new File(FILE_1), new File(FILE_2));
+ assertThat(op.mainSourceDirectories()).as("File...").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+
+ op.mainSourceDirectories(FILE_1, FILE_2);
+ assertThat(op.mainSourceDirectories()).as("String...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+
+ op = op.mainSourceDirectories(Path.of(FILE_1), Path.of(FILE_2));
+ assertThat(op.mainSourceDirectories()).as("Path...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+
+ op.mainSourceDirectoriesPaths(List.of(new File(FILE_1).toPath(), new File(FILE_2).toPath()));
+ assertThat(op.mainSourceDirectories()).as("List(Path...)")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+
+ op.mainSourceDirectoriesStrings(List.of(FILE_1, FILE_2));
+ assertThat(op.mainSourceDirectories()).as("List(String...)")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceDirectories().clear();
+ }
+
+ @Test
+ void testMainSourceFiles() {
+ var op = new CompileKotlinOperation();
+
+ op.mainSourceFiles(List.of(new File(FILE_1), new File(FILE_2)));
+ assertThat(op.mainSourceFiles()).as("List(File...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+
+ op.mainSourceFiles(new File(FILE_1), new File(FILE_2));
+ assertThat(op.mainSourceFiles()).as("File...").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+
+ op.mainSourceFiles(FILE_1, FILE_2);
+ assertThat(op.mainSourceFiles()).as("String...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+
+ op = op.mainSourceFiles(Path.of(FILE_1), Path.of(FILE_2));
+ assertThat(op.mainSourceFiles()).as("Path...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+
+ op.mainSourceFilesPaths(List.of(new File(FILE_1).toPath(), new File(FILE_2).toPath()));
+ assertThat(op.mainSourceFiles()).as("List(Path...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+
+ op.mainSourceFilesStrings(List.of(FILE_1, FILE_2));
+ assertThat(op.mainSourceFiles()).as("List(String...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.mainSourceFiles().clear();
+ }
+
@Test
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
void testPlugins() {
@@ -162,6 +352,8 @@ class CompileKotlinOperationTest {
.fromProject(new BaseProject())
.plugins(CompilerPlugin.ALL_OPEN,
CompilerPlugin.ASSIGNMENT,
+ CompilerPlugin.COMPOSE,
+ CompilerPlugin.KOTLIN_IMPORTS_DUMPER,
CompilerPlugin.KOTLINX_SERIALIZATION,
CompilerPlugin.KOTLIN_SERIALIZATION,
CompilerPlugin.LOMBOK,
@@ -169,8 +361,87 @@ class CompileKotlinOperationTest {
CompilerPlugin.POWER_ASSERT,
CompilerPlugin.SAM_WITH_RECEIVER);
- for (var p : op.plugins()) {
- assertThat(new File(p)).as(p).exists();
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ for (var p : op.plugins()) {
+ softly.assertThat(new File(p)).as(p).exists();
+ }
}
}
+
+ @Test
+ void testTestSourceDirectories() {
+ var op = new CompileKotlinOperation();
+
+ op.testSourceDirectories(List.of(new File(FILE_1), new File(FILE_2)));
+ assertThat(op.testSourceDirectories()).as("List(File...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+
+ op.testSourceDirectories(new File(FILE_1), new File(FILE_2));
+ assertThat(op.testSourceDirectories()).as("File...").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+
+ op.testSourceDirectories(FILE_1, FILE_2);
+ assertThat(op.testSourceDirectories()).as("String...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+
+ op = op.testSourceDirectories(Path.of(FILE_1), Path.of(FILE_2));
+ assertThat(op.testSourceDirectories()).as("Path...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+
+ op.testSourceDirectoriesPaths(List.of(new File(FILE_1).toPath(), new File(FILE_2).toPath()));
+ assertThat(op.testSourceDirectories()).as("List(Path...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+
+ op.testSourceDirectoriesStrings(List.of(FILE_1, FILE_2));
+ assertThat(op.testSourceDirectories()).as("List(String...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceDirectories().clear();
+ }
+
+ @Test
+ void testTestSourceFiles() {
+ var op = new CompileKotlinOperation();
+
+ op.testSourceFiles(List.of(new File(FILE_1), new File(FILE_2)));
+ assertThat(op.testSourceFiles()).as("List(File...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+
+ op.testSourceFiles(new File(FILE_1), new File(FILE_2));
+ assertThat(op.testSourceFiles()).as("File...").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+
+ op.testSourceFiles(FILE_1, FILE_2);
+ assertThat(op.testSourceFiles()).as("String...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+
+ op = op.testSourceFiles(Path.of(FILE_1), Path.of(FILE_2));
+ assertThat(op.testSourceFiles()).as("Path...")
+ .containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+
+ op.testSourceFilesPaths(List.of(new File(FILE_1).toPath(), new File(FILE_2).toPath()));
+ assertThat(op.testSourceFiles()).as("List(Path...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+
+ op.testSourceFilesStrings(List.of(FILE_1, FILE_2));
+ assertThat(op.testSourceFiles()).as("List(String...)").containsExactly(new File(FILE_1), new File(FILE_2));
+ op.testSourceFiles().clear();
+ }
+
+ @Test
+ void testWorkDir() {
+ var foo = new File("foo");
+ var bar = new File("bar");
+
+ var op = new CompileKotlinOperation().workDir(foo);
+ assertThat(op.workDir()).as("as file").isEqualTo(foo);
+
+ op = op.workDir(bar.toPath());
+ assertThat(op.workDir()).as("as path").isEqualTo(bar);
+
+ op = new CompileKotlinOperation().workDir("foo");
+ assertThat(op.workDir()).as("as string").isEqualTo(foo);
+ }
}
diff --git a/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java b/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java
index 25df90b..c6e6965 100644
--- a/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.java
+++ b/src/test/java/rife/bld/extension/kotlin/CompileOptionsTest.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,11 +16,15 @@
package rife.bld.extension.kotlin;
+import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
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.ArrayList;
import java.util.Arrays;
@@ -44,12 +48,10 @@ class CompileOptionsTest {
}
@Test
- @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
+ @SuppressWarnings("PMD.UnitTestShouldIncludeAssert")
void testArgs() {
var options = new CompileOptions()
.apiVersion("11")
- .argFile(new File("file.txt"), new File("file2.txt"))
- .classpath(new File("path1"), new File("path2"))
.javaParameters(true)
.jvmTarget("11")
.includeRuntime(true)
@@ -68,12 +70,11 @@ class CompileOptionsTest {
.progressive(true)
.scriptTemplates("name", "name2")
.verbose(true)
- .wError(true);
+ .wError(true)
+ .wExtra(true);
var matches = List.of(
"-api-version", "11",
- "@" + localPath("file.txt"), "@" + localPath("file2.txt"),
- "-classpath", localPath("path1", "path2"),
"-java-parameters",
"-jvm-target", "11",
"-include-runtime",
@@ -94,23 +95,26 @@ class CompileOptionsTest {
"-progressive",
"-script-templates", "name,name2",
"-verbose",
- "-Werror");
+ "-Werror",
+ "-Wextra");
var args = new ArrayList>();
args.add(options.args());
args.add(options.apiVersion(11).jvmTarget(11).args());
- for (var a : args) {
- IntStream.range(0, a.size()).forEach(i -> assertThat(a.get(i)).isEqualTo(matches.get(i)));
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ for (var a : args) {
+ IntStream.range(0, a.size()).forEach(i -> softly.assertThat(a.get(i))
+ .as(a.get(i) + " == " + matches.get(i)).isEqualTo(matches.get(i)));
+ }
}
}
@Test
void testArgsCollections() {
- var advanceOptions = List.of("Xoption1", "Xoption2");
+ var advanceOptions = List.of("-Xoption1", "option=2");
var argFile = List.of(new File("arg1.txt"), new File("arg2.txt"));
var classpath = List.of(new File("path1"), new File("path2"));
- var jvmOptions = List.of("option1", "option2");
var optIn = List.of("opt1", "opt2");
var options = List.of("-foo", "-bar");
var plugin = List.of("id:name:value", "id2:name2:value2");
@@ -120,7 +124,6 @@ class CompileOptionsTest {
.advancedOptions(advanceOptions)
.argFile(argFile)
.classpath(classpath)
- .jvmOptions(jvmOptions)
.noStdLib(false)
.optIn(optIn)
.options(options)
@@ -131,22 +134,22 @@ class CompileOptionsTest {
op.plugin(p[0], p[1], p[2]);
});
- assertThat(op.advancedOptions()).as("advancedOptions")
- .hasSize(advanceOptions.size()).containsAll(advanceOptions);
- assertThat(op.argFile()).as("argFile")
- .hasSize(argFile.size()).containsAll(argFile);
- assertThat(op.classpath()).as("classpath")
- .hasSize(classpath.size()).containsAll(classpath);
- assertThat(op.jvmOptions()).as("jvmOptions")
- .hasSize(jvmOptions.size()).containsAll(jvmOptions);
- assertThat(op.optIn()).as("optIn")
- .hasSize(optIn.size()).containsAll(optIn);
- assertThat(op.options()).as("options")
- .hasSize(options.size()).containsAll(options);
- assertThat(op.plugin()).as("plugin")
- .hasSize(plugin.size()).containsAll(plugin);
- assertThat(op.scriptTemplates()).as("scriptTemplates")
- .hasSize(scriptTemplates.size()).containsAll(scriptTemplates);
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(op.advancedOptions()).as("advancedOptions")
+ .hasSize(advanceOptions.size()).containsAll(advanceOptions);
+ softly.assertThat(op.argFile()).as("argFile")
+ .hasSize(argFile.size()).containsAll(argFile);
+ softly.assertThat(op.classpath()).as("classpath")
+ .hasSize(classpath.size()).containsAll(classpath);
+ softly.assertThat(op.optIn()).as("optIn")
+ .hasSize(optIn.size()).containsAll(optIn);
+ softly.assertThat(op.options()).as("options")
+ .hasSize(options.size()).containsAll(options);
+ softly.assertThat(op.plugin()).as("plugin")
+ .hasSize(plugin.size()).containsAll(plugin);
+ softly.assertThat(op.scriptTemplates()).as("scriptTemplates")
+ .hasSize(scriptTemplates.size()).containsAll(scriptTemplates);
+ }
var matches = List.of(
'@' + localPath("arg1.txt"), '@' + localPath("arg2.txt"),
@@ -157,24 +160,52 @@ class CompileOptionsTest {
"-foo", "-bar",
"-script-templates",
"temp1,temp2",
- "-XXoption1", "-XXoption2",
+ "-Xoption1", "-Xoption=2",
"-P", "plugin:id:name:value",
"-P", "plugin:id2:name2:value2");
- var args = op.args();
- for (var arg : args) {
- var found = false;
- for (var match : matches) {
- if (match.equals(arg)) {
- found = true;
- break;
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ var args = op.args();
+ for (var arg : args) {
+ var found = false;
+ for (var match : matches) {
+ if (match.equals(arg)) {
+ found = true;
+ break;
+ }
}
+ softly.assertThat(found).as(arg + " not found.").isTrue();
}
- assertThat(found).as(arg).isTrue();
}
}
@Test
+ void testArgsFile() {
+ var foo = new File("foo.txt");
+ var bar = new File("bar.txt");
+ var options = new CompileOptions();
+
+ options = options.argFile(foo);
+ assertThat(options.argFile()).contains(foo);
+ options.argFile().clear();
+ assertThat(options.argFile()).isEmpty();
+
+ options.argFile(foo, bar);
+ assertThat(options.argFile()).contains(foo, bar);
+ options.argFile().clear();
+ assertThat(options.argFile()).isEmpty();
+
+ options = options.argFile(foo.toPath(), bar.toPath());
+ assertThat(options.argFile()).contains(foo, bar);
+ options.argFile().clear();
+ assertThat(options.argFile()).isEmpty();
+
+ options = options.argFile(foo.getAbsolutePath(), bar.getAbsolutePath());
+ assertThat(options.argFile()).contains(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
+ }
+
+ @Test
+ @EnabledOnOs(OS.LINUX)
void testCheckAllParams() throws IOException {
var args = Files.readAllLines(Paths.get("src", "test", "resources", "kotlinc-args.txt"));
@@ -182,15 +213,14 @@ class CompileOptionsTest {
var params = new CompileOptions()
.advancedOptions("Xoption")
- .argFile("file")
- .classpath("classpath")
+ .apiVersion("11")
.expression("expression")
- .jvmOptions("option")
.includeRuntime(true)
.javaParameters(true)
.jdkHome("jdkhome")
.jvmTarget(12)
.kotlinHome("kotlin")
+ .languageVersion("1.0")
.moduleName("moduleName")
.noJdk(true)
.noReflect(true)
@@ -203,17 +233,161 @@ class CompileOptionsTest {
.progressive(true)
.scriptTemplates("template")
.verbose(true)
- .wError(true);
+ .wError(true)
+ .wExtra(true);
- for (var p : args) {
- var found = false;
- for (var a : params.args()) {
- if (a.startsWith(p)) {
- found = true;
- break;
+ var skipArgs = List.of("-J", "-classpath", "@");
+ assertThat(args).as(skipArgs + " not found.").containsAll(skipArgs);
+ args.removeAll(skipArgs);
+
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ for (var p : args) {
+ var found = false;
+ for (var a : params.args()) {
+ if (a.startsWith(p)) {
+ found = true;
+ break;
+ }
}
+ softly.assertThat(found).as(p + " not found.").isTrue();
}
- assertThat(found).as(p + " not found.").isTrue();
+ }
+ }
+
+ @Test
+ void testClasspath() {
+ var foo = new File("foo.txt");
+ var bar = new File("bar.txt");
+ var options = new CompileOptions();
+
+ options = options.classpath(foo);
+ assertThat(options.classpath()).as("File").containsExactly(foo);
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+
+ options.classpath(foo, bar);
+ assertThat(options.classpath()).as("File...").containsExactly(foo, bar);
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+
+ options.classpath(List.of(foo, bar));
+ assertThat(options.classpath()).as("List(File...)").containsExactly(foo, bar);
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+
+ options = options.classpath(foo.toPath(), bar.toPath());
+ assertThat(options.classpath()).as("Path...").containsExactly(foo, bar);
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+
+ options = options.classpathPaths(List.of(foo.toPath(), bar.toPath()));
+ assertThat(options.classpath()).as("List(Path...)").containsExactly(foo, bar);
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+
+ options.classpath(foo.getAbsolutePath(), bar.getAbsolutePath());
+ assertThat(options.classpath()).as("String...")
+ .containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
+ options.classpath().clear();
+ assertThat(options.argFile()).isEmpty();
+
+ options.classpathStrings(List.of(foo.getAbsolutePath(), bar.getAbsolutePath()));
+ assertThat(options.classpath()).as("List(String...)")
+ .containsExactly(new File(foo.getAbsolutePath()), new File(bar.getAbsolutePath()));
+ }
+
+ @Test
+ void testJdkHome() {
+ var foo = new File("foo.txt");
+ var options = new CompileOptions();
+
+ options.jdkHome(foo);
+ assertThat(options.jdkHome()).isEqualTo(foo);
+
+ options = options.jdkHome(foo.toPath());
+ assertThat(options.jdkHome()).isEqualTo(foo);
+
+ options.jdkHome(foo.getAbsolutePath());
+ assertThat(options.jdkHome().getAbsolutePath()).isEqualTo(foo.getAbsolutePath());
+ }
+
+ @Test
+ void testKotlinHome() {
+ var foo = new File("foo.txt");
+ var options = new CompileOptions();
+
+ options.kotlinHome(foo);
+ assertThat(options.kotlinHome()).isEqualTo(foo);
+
+ options = options.kotlinHome(foo.toPath());
+ assertThat(options.kotlinHome()).isEqualTo(foo);
+
+ options.kotlinHome(foo.getAbsolutePath());
+ assertThat(options.kotlinHome().getAbsolutePath()).isEqualTo(foo.getAbsolutePath());
+ }
+
+ @Test
+ void testOptions() {
+ var options = new CompileOptions()
+ .advancedOptions("xopt1", "xopt2")
+ .apiVersion("11")
+ .argFile(Path.of("args.txt"))
+ .classpath("classpath")
+ .expression("expression")
+ .includeRuntime(true)
+ .javaParameters(true)
+ .jdkHome("jdk-home")
+ .jdkRelease(22)
+ .jvmTarget("9")
+ .kotlinHome("kotlin-home")
+ .languageVersion("1.0")
+ .moduleName("module")
+ .noJdk(true)
+ .noReflect(true)
+ .noStdLib(true)
+ .noWarn(true)
+ .optIn("opt1", "opt2")
+ .options("-foo", "-bar")
+ .path(Path.of("path"))
+ .plugin("id", "name", "value")
+ .progressive(true)
+ .scriptTemplates("name", "name2")
+ .verbose(true)
+ .wError(true)
+ .wExtra(true);
+
+ try (var softly = new AutoCloseableSoftAssertions()) {
+ softly.assertThat(options.advancedOptions()).containsExactly("xopt1", "xopt2");
+ softly.assertThat(options.apiVersion()).isEqualTo("11");
+ softly.assertThat(options.argFile()).containsExactly(new File("args.txt"));
+ softly.assertThat(options.classpath()).containsExactly(new File("classpath"));
+ softly.assertThat(options.expression()).isEqualTo("expression");
+ softly.assertThat(options.isIncludeRuntime()).isTrue();
+ softly.assertThat(options.isJavaParameters()).isTrue();
+ softly.assertThat(options.isNoJdk()).isTrue();
+ softly.assertThat(options.isNoReflect()).isTrue();
+ softly.assertThat(options.isNoStdLib()).isTrue();
+ softly.assertThat(options.isNoWarn()).isTrue();
+ softly.assertThat(options.isProgressive()).isTrue();
+ softly.assertThat(options.isVerbose()).isTrue();
+ softly.assertThat(options.jdkHome()).isEqualTo(new File("jdk-home"));
+ softly.assertThat(options.jdkRelease()).isEqualTo("22");
+ softly.assertThat(options.jvmTarget()).isEqualTo("9");
+ softly.assertThat(options.kotlinHome()).isEqualTo(new File("kotlin-home"));
+ softly.assertThat(options.languageVersion()).isEqualTo("1.0");
+ softly.assertThat(options.moduleName()).isEqualTo("module");
+ softly.assertThat(options.optIn()).containsExactly("opt1", "opt2");
+ softly.assertThat(options.options()).containsExactly("-foo", "-bar");
+ softly.assertThat(options.path()).isEqualTo(new File("path"));
+ softly.assertThat(options.plugin()).containsExactly("id:name:value");
+ softly.assertThat(options.scriptTemplates()).containsExactly("name", "name2");
+ softly.assertThat(options.isWError()).isTrue();
+ softly.assertThat(options.isWExtra()).isTrue();
}
}
}
diff --git a/src/test/java/rife/bld/extension/kotlin/JvmOptionsTest.java b/src/test/java/rife/bld/extension/kotlin/JvmOptionsTest.java
new file mode 100644
index 0000000..6f8474f
--- /dev/null
+++ b/src/test/java/rife/bld/extension/kotlin/JvmOptionsTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.kotlin;
+
+import org.junit.jupiter.api.Test;
+import rife.bld.extension.CompileKotlinOperation;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
+class JvmOptionsTest {
+ @Test
+ void testop() {
+ var op = new CompileKotlinOperation().jvmOptions(new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED));
+ assertThat(op.jvmOptions()).as(JvmOptions.ALL_UNNAMED).containsExactly("--enable-native-access=ALL-UNNAMED");
+
+ op = new CompileKotlinOperation().jvmOptions(new JvmOptions().enableNativeAccess("m1", "m2"));
+ assertThat(op.jvmOptions()).as("m1,m2").containsExactly("--enable-native-access=m1,m2");
+ }
+
+ @Test
+ void testEnableNativeAccess() {
+ var options = new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED);
+ assertThat(options).as(JvmOptions.ALL_UNNAMED).containsExactly("--enable-native-access=ALL-UNNAMED");
+
+ options = new JvmOptions().enableNativeAccess("m1");
+ assertThat(options).as("m1").containsExactly("--enable-native-access=m1");
+
+ options = new JvmOptions().enableNativeAccess("m1", "m2");
+ assertThat(options).as("m1,m2").containsExactly("--enable-native-access=m1,m2");
+ }
+
+ @Test
+ void testIllegalNativeAccess() {
+ var options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.ALLOW);
+ assertThat(options).as("ALLOW").containsExactly("--illegal-native-access=allow");
+
+ options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.DENY);
+ assertThat(options).as("DENY").containsExactly("--illegal-native-access=deny");
+
+ options = new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.WARN);
+ assertThat(options).as("WARN").containsExactly("--illegal-native-access=warn");
+ }
+
+ @Test
+ void testJvmOptions() {
+ var op = new CompileKotlinOperation().jvmOptions("option1", "option2");
+ assertThat(op.jvmOptions()).as("option1,option2").containsExactly("option1", "option2");
+
+ op = new CompileKotlinOperation().jvmOptions(List.of("option1", "option2"));
+ assertThat(op.jvmOptions()).as("List.of(option1,option2)").containsExactly("option1", "option2");
+
+ op = op.jvmOptions(new JvmOptions().enableNativeAccess(JvmOptions.ALL_UNNAMED));
+ assertThat(op.jvmOptions()).as("List.of(option1,option2,ALL_UNNAMED)")
+ .containsExactly("option1", "option2", "--enable-native-access=ALL-UNNAMED");
+
+ op = op.jvmOptions(new JvmOptions().illegalNativeAccess(JvmOptions.NativeAccess.ALLOW));
+ assertThat(op.jvmOptions()).as("allow")
+ .containsExactly("option1", "option2", "--enable-native-access=ALL-UNNAMED",
+ "--illegal-native-access=allow");
+ }
+}
diff --git a/src/test/resources/argfile.txt b/src/test/resources/argfile.txt
new file mode 100644
index 0000000..d128d62
--- /dev/null
+++ b/src/test/resources/argfile.txt
@@ -0,0 +1,3 @@
+-Xjdk-release=17 -no-reflect
+
+-progressive
diff --git a/src/test/resources/argfile2.txt b/src/test/resources/argfile2.txt
new file mode 100644
index 0000000..93f9181
--- /dev/null
+++ b/src/test/resources/argfile2.txt
@@ -0,0 +1 @@
+-include-runtime
\ No newline at end of file
diff --git a/src/test/resources/kotlinc-args.txt b/src/test/resources/kotlinc-args.txt
index 1f49a77..e764231 100644
--- a/src/test/resources/kotlinc-args.txt
+++ b/src/test/resources/kotlinc-args.txt
@@ -1,4 +1,5 @@
@
+-api-version
-classpath
-d
-expression
@@ -8,6 +9,7 @@
-jdk-home
-jvm-target
-kotlin-home
+-language-version
-module-name
-no-jdk
-no-reflect
@@ -20,4 +22,5 @@
-script-templates
-verbose
-Werror
+-Wextra
-X