From d2df2696d6d53eba9e117595c4b6988b51478a43 Mon Sep 17 00:00:00 2001
From: SergeyDatskiv <77079268+SergeyDatskiv@users.noreply.github.com>
Date: Thu, 28 Nov 2024 17:31:26 +0100
Subject: [PATCH 1/6] Java path for kotlin tests compilation on Windows
 machines (#412)

---
 .../core/test/kotlin/KotlinTestCompiler.kt    |  9 +++-
 .../tools/factories/TestCompilerFactory.kt    | 50 +++++++++++--------
 2 files changed, 37 insertions(+), 22 deletions(-)

diff --git a/core/src/main/kotlin/org/jetbrains/research/testspark/core/test/kotlin/KotlinTestCompiler.kt b/core/src/main/kotlin/org/jetbrains/research/testspark/core/test/kotlin/KotlinTestCompiler.kt
index f7e38ea81..536555f5d 100644
--- a/core/src/main/kotlin/org/jetbrains/research/testspark/core/test/kotlin/KotlinTestCompiler.kt
+++ b/core/src/main/kotlin/org/jetbrains/research/testspark/core/test/kotlin/KotlinTestCompiler.kt
@@ -13,6 +13,7 @@ class KotlinTestCompiler(
     libPaths: List<String>,
     junitLibPaths: List<String>,
     kotlinSDKHomeDirectory: String,
+    private val javaHomeDirectoryPath: String,
 ) : TestCompiler(libPaths, junitLibPaths) {
     private val logger = KotlinLogging.logger { this::class.java }
     private val kotlinc: String
@@ -32,7 +33,6 @@ class KotlinTestCompiler(
                  * as failed compilation because `kotlinc` will complain about
                  * `java` command missing in PATH.
                  *
-                 * TODO(vartiukhov): find a way to locate `java` on Windows
                  */
                 val isCompilerName = if (DataFilesUtil.isWindows()) {
                     it.name.equals("kotlinc")
@@ -55,9 +55,14 @@ class KotlinTestCompiler(
         logger.info { "[KotlinTestCompiler] Compiling ${path.substringAfterLast('/')}" }
 
         val classPaths = "\"${getClassPaths(projectBuildPath)}\""
+
+        // We need to ensure JAVA is in the path variable
+        // See: https://github.com/JetBrains-Research/TestSpark/issues/410
+        val setJavaPathOnWindows = "set PATH=%PATH%;$javaHomeDirectoryPath\\bin\\&&"
+
         // Compile file
         // See: https://github.com/JetBrains-Research/TestSpark/issues/402
-        val kotlinc = if (DataFilesUtil.isWindows()) "\"$kotlinc\"" else "'$kotlinc'"
+        val kotlinc = if (DataFilesUtil.isWindows()) "$setJavaPathOnWindows\"$kotlinc\"" else "'$kotlinc'"
 
         val executionResult = CommandLineRunner.run(
             arrayListOf(
diff --git a/src/main/kotlin/org/jetbrains/research/testspark/tools/factories/TestCompilerFactory.kt b/src/main/kotlin/org/jetbrains/research/testspark/tools/factories/TestCompilerFactory.kt
index aa9a12aef..025761b24 100644
--- a/src/main/kotlin/org/jetbrains/research/testspark/tools/factories/TestCompilerFactory.kt
+++ b/src/main/kotlin/org/jetbrains/research/testspark/tools/factories/TestCompilerFactory.kt
@@ -24,33 +24,43 @@ object TestCompilerFactory {
 
         // TODO add the warning window that for Java we always need the javaHomeDirectoryPath
         return when (language) {
-            SupportedLanguage.Java -> createJavaCompiler(project, libraryPaths, junitLibraryPaths, javaHomeDirectory)
-            SupportedLanguage.Kotlin -> createKotlinCompiler(libraryPaths, junitLibraryPaths)
+            SupportedLanguage.Java -> {
+                val javaSDKHomePath = findJavaSDKHomePath(javaHomeDirectory, project)
+                JavaTestCompiler(libraryPaths, junitLibraryPaths, javaSDKHomePath)
+            }
+            SupportedLanguage.Kotlin -> {
+                // Kotlinc relies on java to compile kotlin files.
+                val javaSDKHomePath = findJavaSDKHomePath(javaHomeDirectory, project)
+                // kotlinc should be under `[kotlinSDKHomeDirectory]/bin/kotlinc`
+                val kotlinSDKHomeDirectory = KotlinPluginLayout.kotlinc.absolutePath
+                KotlinTestCompiler(libraryPaths, junitLibraryPaths, kotlinSDKHomeDirectory, javaSDKHomePath)
+            }
         }
     }
 
-    private fun createJavaCompiler(
+    /**
+     * Finds the home path of the Java SDK.
+     *
+     * @param javaHomeDirectory The directory where Java SDK is installed. If null, the project's configured SDK path is used.
+     * @param project The project for which the Java SDK home path is being determined.
+     * @return The home path of the Java SDK.
+     * @throws JavaSDKMissingException If no Java SDK is configured for the project.
+     */
+    private fun findJavaSDKHomePath(
+        javaHomeDirectory: String?,
         project: Project,
-        libraryPaths: List<String>,
-        junitLibraryPaths: List<String>,
-        javaHomeDirectory: String? = null,
-    ): JavaTestCompiler {
-        val javaSDKHomePath = javaHomeDirectory
-            ?: ProjectRootManager.getInstance(project).projectSdk?.homeDirectory?.path
+    ): String {
+        val javaSDKHomePath =
+            javaHomeDirectory
+                ?: ProjectRootManager
+                    .getInstance(project)
+                    .projectSdk
+                    ?.homeDirectory
+                    ?.path
 
         if (javaSDKHomePath == null) {
             throw JavaSDKMissingException(LLMMessagesBundle.get("javaSdkNotConfigured"))
         }
-
-        return JavaTestCompiler(libraryPaths, junitLibraryPaths, javaSDKHomePath)
-    }
-
-    private fun createKotlinCompiler(
-        libraryPaths: List<String>,
-        junitLibraryPaths: List<String>,
-    ): KotlinTestCompiler {
-        // kotlinc should be under `[kotlinSDKHomeDirectory]/bin/kotlinc`
-        val kotlinSDKHomeDirectory = KotlinPluginLayout.kotlinc.absolutePath
-        return KotlinTestCompiler(libraryPaths, junitLibraryPaths, kotlinSDKHomeDirectory)
+        return javaSDKHomePath
     }
 }

From 07d41c14bb29fd8bad992429f3a067187eb829ae Mon Sep 17 00:00:00 2001
From: Vladislav Artiukhov <vladislav0art.work@gmail.com>
Date: Tue, 3 Dec 2024 22:44:48 +0000
Subject: [PATCH 2/6] feat: uncomment project resolving logic

---
 .../testspark/appstarter/ProjectApplicationUtils.kt | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/main/kotlin/org/jetbrains/research/testspark/appstarter/ProjectApplicationUtils.kt b/src/main/kotlin/org/jetbrains/research/testspark/appstarter/ProjectApplicationUtils.kt
index 4fd7a12fa..043e6eba2 100644
--- a/src/main/kotlin/org/jetbrains/research/testspark/appstarter/ProjectApplicationUtils.kt
+++ b/src/main/kotlin/org/jetbrains/research/testspark/appstarter/ProjectApplicationUtils.kt
@@ -13,11 +13,13 @@ import com.intellij.openapi.application.ModalityState
 import com.intellij.openapi.application.ex.ApplicationManagerEx
 import com.intellij.openapi.progress.util.ProgressIndicatorBase
 import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ProjectManager
 import com.intellij.openapi.util.Disposer
 import com.intellij.openapi.util.io.FileUtil
 import com.intellij.openapi.vfs.LocalFileSystem
 import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.startup.StartupManager
 import kotlinx.coroutines.runBlocking
 import org.jetbrains.idea.maven.MavenCommandLineInspectionProjectConfigurator
 import org.jetbrains.idea.maven.project.MavenProjectsManager
@@ -25,6 +27,7 @@ import org.jetbrains.plugins.gradle.GradleCommandLineProjectConfigurator
 import org.slf4j.LoggerFactory
 import java.nio.file.Path
 import java.util.function.Predicate
+import kotlin.coroutines.resume
 import kotlin.coroutines.suspendCoroutine
 
 class ProjectConfiguratorException : Exception {
@@ -160,15 +163,17 @@ object ProjectApplicationUtils {
         logger.info("Closing project $project...")
         ApplicationManager.getApplication().assertIsNonDispatchThread()
         // ToDo: move headless mode to another branch
-//        ApplicationManager.getApplication().invokeAndWait {
-//            ProjectManagerEx.getInstanceEx().forceCloseProject(project)
-//        }
+        ApplicationManager.getApplication().invokeAndWait {
+            ProjectManager.getInstance().closeAndDispose(project)
+            // TODO: what is ProjectManagerEx?
+            // ProjectManagerEx.getInstanceEx().forceCloseProject(project)
+        }
     }
 
     private suspend fun waitAllStartupActivitiesPassed(project: Project): Unit = suspendCoroutine {
         logger.info("Waiting all startup activities passed $project...")
         // ToDo: move headless mode to another branch
-//        StartupManager.getInstance(project).runAfterOpened { it.resume(Unit) }
+        StartupManager.getInstance(project).runAfterOpened { it.resume(Unit) }
         waitForInvokeLaterActivities()
     }
 

From 3bdff3b88fd2f47849f1e21da60f7f7a68686ea8 Mon Sep 17 00:00:00 2001
From: Vladislav Artiukhov <vladislav0art.work@gmail.com>
Date: Tue, 3 Dec 2024 22:45:32 +0000
Subject: [PATCH 3/6] feat: create headless2 task using modern intellij
 platform API

---
 build.gradle.kts | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index 0f44089cb..da78414e4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -36,6 +36,7 @@ plugins {
     // Gradle Qodana Plugin
 //    id("org.jetbrains.qodana") version "0.1.13"
 }
+
 group = properties("pluginGroup")
 version = properties("pluginVersion")
 
@@ -46,6 +47,8 @@ repositories {
     // See https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-repositories-extension.html#default-repositories
     intellijPlatform {
         defaultRepositories()
+        intellijDependencies()
+        localPlatformArtifacts()
     }
     maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
     maven("https://www.jetbrains.com/intellij-repository/snapshots")
@@ -152,6 +155,8 @@ dependencies {
         "hasGrazieAccessCompileOnly"(project(":core"))
     }
 
+    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
+
     // https://central.sonatype.com/artifact/io.github.oshai/kotlin-logging-jvm/overview
     implementation("io.github.oshai:kotlin-logging-jvm:6.0.3")
 
@@ -226,7 +231,7 @@ intellijPlatform {
     // See https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-extension.html#intellijPlatform-pluginVerification-ides
     pluginVerification {
         ides {
-            recommended()
+            // recommended()
             select {
                 types = listOf(IntelliJPlatformType.IntellijIdeaUltimate)
                 channels = listOf(ProductRelease.Channel.RELEASE)
@@ -256,7 +261,6 @@ changelog {
 // }
 
 tasks {
-
     compileKotlin {
         dependsOn("updateEvosuite")
         dependsOn("copyJUnitRunnerLib")
@@ -391,6 +395,7 @@ abstract class UpdateEvoSuite : DefaultTask() {
 tasks.register<UpdateEvoSuite>("updateEvosuite") {
     evoSuiteVersion = properties("evosuiteVersion")
 }
+
 /**
  * Copies the JUnitRunner.jar file to the lib directory of the project.
  * This task depends on the "JUnitRunner" module being built beforehand.
@@ -416,6 +421,37 @@ tasks.register<Copy>("copyJUnitRunnerLib") {
  */
 fun String?.orDefault(default: String): String = this ?: default
 
+
+val headless2 by intellijPlatformTesting.runIde.registering {
+    type = IntelliJPlatformType.IntellijIdeaCommunity
+    version = properties("platformVersion")
+
+    val root: String? by project
+    val file: String? by project
+    val cut: String? by project
+    val cp: String? by project
+    val junitv: String? by project
+    val llm: String? by project
+    val token: String? by project
+    val prompt: String? by project
+    val out: String? by project
+    val enableCoverage: String? by project
+
+    task {
+        jvmArgumentProviders += CommandLineArgumentProvider {
+            listOf(
+                "-Xmx16G",
+                "-Djava.awt.headless=true",
+                "--add-exports",
+                "java.base/jdk.internal.vm=ALL-UNNAMED",
+                "-Didea.system.path",
+            )
+        }
+
+        args = listOfNotNull("testspark", root, file, cut, cp, junitv, llm, token, prompt, out, enableCoverage.orDefault("false"))
+    }
+}
+
 /**
  * This code sets up a Gradle task for running the plugin in headless mode
  *

From d7989f6cf14dd52d458698f9c90bf9363b2034ac Mon Sep 17 00:00:00 2001
From: Vladislav Artiukhov <vladislav0art.work@gmail.com>
Date: Tue, 3 Dec 2024 23:14:17 +0000
Subject: [PATCH 4/6] feat: add .intellijPlatform into gitignore

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index aed022b20..faef4522a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ lib/evosuite-*.jar
 lib/JUnitRunner.jar
 **/evosuite-tests/
 *.DS_Store
+.intellijPlatform
 
 # Test projects
 src/test/resources/project/.idea/

From d07f602828ce17c6a0a8125ce2d83d08b187ea14 Mon Sep 17 00:00:00 2001
From: Vladislav Artiukhov <vladislav0art.work@gmail.com>
Date: Tue, 3 Dec 2024 23:14:44 +0000
Subject: [PATCH 5/6] dep: add  dependency

---
 build.gradle.kts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index da78414e4..fc213b800 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -69,6 +69,7 @@ repositories {
 }
 
 if (spaceCredentialsProvided()) {
+    println("WIth space creds!")
     // Add the new source set
     val hasGrazieAccess = sourceSets.create("hasGrazieAccess")
     // add output of main source set to new source set class path
@@ -155,7 +156,7 @@ dependencies {
         "hasGrazieAccessCompileOnly"(project(":core"))
     }
 
-    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.0")
+    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.23")
 
     // https://central.sonatype.com/artifact/io.github.oshai/kotlin-logging-jvm/overview
     implementation("io.github.oshai:kotlin-logging-jvm:6.0.3")

From a29e23902561e1e3df08ba9fd724e0f005c96a8f Mon Sep 17 00:00:00 2001
From: Vladislav Artiukhov <vladislav0art.work@gmail.com>
Date: Tue, 3 Dec 2024 23:15:11 +0000
Subject: [PATCH 6/6] version(gradle): update gradle version to 8.9

---
 gradle/wrapper/gradle-wrapper.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0d1842103..19cfad969 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists