From 0fceb591848b8a45bed1ecdd44757f988f99d4d6 Mon Sep 17 00:00:00 2001 From: Hello-zoka Date: Fri, 8 Nov 2024 17:32:36 +0100 Subject: [PATCH] Removing headless from development branch --- build.gradle.kts | 38 +-- runTestSparkHeadless.sh | 31 -- .../testspark/appstarter/TestSparkStarter.kt | 307 ------------------ .../progress/HeadlessProgressIndicator.kt | 31 -- src/main/resources/META-INF/plugin.xml | 5 - 5 files changed, 1 insertion(+), 411 deletions(-) delete mode 100644 runTestSparkHeadless.sh delete mode 100644 src/main/kotlin/org/jetbrains/research/testspark/appstarter/TestSparkStarter.kt delete mode 100644 src/main/kotlin/org/jetbrains/research/testspark/progress/HeadlessProgressIndicator.kt diff --git a/build.gradle.kts b/build.gradle.kts index 0f44089cb..52b66288f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,6 @@ import org.jetbrains.changelog.markdownToHTML import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType import org.jetbrains.intellij.platform.gradle.TestFrameworkType import org.jetbrains.intellij.platform.gradle.models.ProductRelease -import org.jetbrains.intellij.platform.gradle.tasks.RunIdeTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.io.FileOutputStream import java.net.URL @@ -236,7 +235,7 @@ intellijPlatform { } freeArgs = listOf( "-mute", - "TemplateWordInPluginId,ForbiddenPluginIdPrefix" + "TemplateWordInPluginId,ForbiddenPluginIdPrefix", ) } } @@ -416,40 +415,5 @@ tasks.register("copyJUnitRunnerLib") { */ fun String?.orDefault(default: String): String = this ?: default -/** - * This code sets up a Gradle task for running the plugin in headless mode - * - * @param root The root directory of the project under test. - * @param file The file containing unit under test. - * @param cut The class under test. - * @param cp The classpath of the project. - * @param llm The model used for the test generation task. - * @param token The token for using LLM. - * @param prompt a txt file containing the LLM's prompt template - * @param out The output directory for the project. - * @param enableCoverage flag to enable/disable coverage computation - */ -tasks.create("headless") { - 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 - - args = listOfNotNull("testspark", root, file, cut, cp, junitv, llm, token, prompt, out, enableCoverage.orDefault("false")) - - jvmArgs( - "-Xmx16G", - "-Djava.awt.headless=true", - "--add-exports", - "java.base/jdk.internal.vm=ALL-UNNAMED", - "-Didea.system.path", - ) -} fun spaceCredentialsProvided() = spaceUsername.isNotEmpty() && spacePassword.isNotEmpty() diff --git a/runTestSparkHeadless.sh b/runTestSparkHeadless.sh deleted file mode 100644 index a5b64f474..000000000 --- a/runTestSparkHeadless.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -# https://stackoverflow.com/a/246128 -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" -if uname -s | grep -iq cygwin; then - DIR=$(cygpath -w "$DIR") - PWD=$(cygpath -w "$PWD") -fi -echo $DIR - -echo "Provided arguments are $@" - -if [ $# -ne "12" ]; then - echo "$# arguments provided, expected 12 arguments in the following order: - 1) Path to the root directory of the project under test (ProjectPath) - 2) Path to the target file (.java file) (it MUST be relative to the ProjectPath) - 3) Qualified name of the class under test (i.e., .) - 4) Classpaths containing the compiled project (separated by ':') - 5) Version of JUnit testing framework (either 4 or 5) - 6) Model name (e.g., GPT-4) - 7) Grazie token - 8) Filepath to a txt-file containing prompt template - 9) Output directory - 10) Enable/disable coverage computation ('true' or 'false') - 11) Space username - 12) Space password" - exit 1 -fi - -echo -Proot="$1" -Pfile="$2" -Pcut="$3" -Pcp="$4" -Pjunitv="$5" -Pllm="$6" -Ptoken="$7" -Pprompt="$8" -Pout="$9" -PenableCoverage="${10}" -Dspace.username="${11}" -Dspace.pass="${12}" -"$DIR/gradlew" -p "$DIR" headless -Proot="$1" -Pfile="$2" -Pcut="$3" -Pcp="$4" -Pjunitv="$5" -Pllm="$6" -Ptoken="$7" -Pprompt="$8" -Pout="$9" -PenableCoverage="${10}" -Dspace.username="${11}" -Dspace.pass="${12}" diff --git a/src/main/kotlin/org/jetbrains/research/testspark/appstarter/TestSparkStarter.kt b/src/main/kotlin/org/jetbrains/research/testspark/appstarter/TestSparkStarter.kt deleted file mode 100644 index ff8580ade..000000000 --- a/src/main/kotlin/org/jetbrains/research/testspark/appstarter/TestSparkStarter.kt +++ /dev/null @@ -1,307 +0,0 @@ -package org.jetbrains.research.testspark.appstarter - -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ApplicationStarter -import com.intellij.openapi.components.service -import com.intellij.openapi.project.DumbService -import com.intellij.openapi.project.Project -import com.intellij.openapi.project.ProjectManager -import com.intellij.openapi.roots.ProjectFileIndex -import com.intellij.openapi.roots.ProjectRootManager -import com.intellij.openapi.util.Disposer -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiManager -import kotlinx.serialization.ExperimentalSerializationApi -import org.jetbrains.research.testspark.bundles.llm.LLMDefaultsBundle -import org.jetbrains.research.testspark.core.data.JUnitVersion -import org.jetbrains.research.testspark.core.data.TestGenerationData -import org.jetbrains.research.testspark.core.monitor.DefaultErrorMonitor -import org.jetbrains.research.testspark.core.test.TestCompiler -import org.jetbrains.research.testspark.core.test.data.CodeType -import org.jetbrains.research.testspark.data.FragmentToTestData -import org.jetbrains.research.testspark.data.ProjectContext -import org.jetbrains.research.testspark.data.llm.JsonEncoding -import org.jetbrains.research.testspark.langwrappers.PsiHelperProvider -import org.jetbrains.research.testspark.progress.HeadlessProgressIndicator -import org.jetbrains.research.testspark.services.LLMSettingsService -import org.jetbrains.research.testspark.services.PluginSettingsService -import org.jetbrains.research.testspark.tools.TestProcessor -import org.jetbrains.research.testspark.tools.TestsExecutionResultManager -import org.jetbrains.research.testspark.tools.ToolUtils -import org.jetbrains.research.testspark.tools.factories.TestCompilerFactory -import org.jetbrains.research.testspark.tools.llm.Llm -import java.io.File -import java.nio.file.Path -import java.nio.file.Paths -import kotlin.system.exitProcess - -/** - * This class is responsible for generating and running tests based on the provided arguments in headless mode. - */ -class TestSparkStarter : ApplicationStarter { - @Deprecated("Specify it as `id` for extension definition in a plugin descriptor") - override val commandName: String = "testspark" - - /** Sets main (start) thread for IDE in headless as not edt. */ - override val requiredModality: Int = ApplicationStarter.NOT_IN_EDT - - @Suppress("TooGenericExceptionCaught") - @OptIn(ExperimentalSerializationApi::class) - override fun main(args: List) { - // Project path - val projectPath = args[1] - // Path to the target file (.java file) - val cutSourceFilePath = Paths.get(projectPath, args[2]).toAbsolutePath() - // CUT name (.) - val classUnderTestName = args[3] - // Paths to compilation output of the project under test (seperated by ':') - val projectClassPath = args[4] - val classPath = "$projectPath${ToolUtils.pathSep}$projectClassPath" - // JUnit Version - val jUnitVersion = args[5] - // Selected model - val model = args[6] - // Token - val token = args[7] - // Filepath to a file containing the prompt template - val promptTemplateFile = args[8] - // Output directory - val output = args[9] - // Run coverage - val runCoverage = args[10].toBoolean() - - val testsExecutionResultManager = TestsExecutionResultManager() - - println("Test generation requested for $projectPath") - - // remove the `.idea` folder in the $projectPath if exists - val ideaFolderPath = "$projectPath${File.separator}.idea" - val ideaFolder = File(ideaFolderPath) - if (ideaFolder.exists()) { - ideaFolder.deleteRecursively() - } - - // open and resolve the project - val project = try { - JvmProjectConfigurator().openProject( - Paths.get(projectPath), - fullResolve = true, - parentDisposable = Disposer.newDisposable(), - ) - } catch (e: Throwable) { - e.printStackTrace(System.err) - exitProcess(1) - } - - ApplicationManager.getApplication().invokeAndWait { - println("Detected project: $project") - // Continue when the project is indexed - println("Indexing project...") - project.let { - DumbService.getInstance(it).runWhenSmart { - try { - // open target file - val cutSourceVirtualFile = - LocalFileSystem.getInstance().findFileByPath(cutSourceFilePath.toString()) ?: run { - println("Couldn't open file $cutSourceFilePath") - exitProcess(1) - } - - // get target PsiClass - val psiFile = PsiManager.getInstance(project).findFile(cutSourceVirtualFile) as PsiJavaFile - val targetPsiClass = detectPsiClass(psiFile.classes, classUnderTestName) ?: run { - println("Couldn't find $classUnderTestName in $cutSourceFilePath") - exitProcess(1) - } - - println("PsiClass ${targetPsiClass.qualifiedName} is detected! Start the test generation process.") - - // Get project SDK - val projectSDKPath = getProjectSdkPath(project) - // update settings - val settingsState = project.getService(LLMSettingsService::class.java).state - settingsState.currentLLMPlatformName = LLMDefaultsBundle.get("grazieName") - settingsState.grazieToken = token - settingsState.grazieModel = model - settingsState.classPrompts = - JsonEncoding.encode(mutableListOf(File(promptTemplateFile).readText())) - settingsState.junitVersion = when (jUnitVersion.filter { it.isDigit() }) { - "4" -> JUnitVersion.JUnit4 - "5" -> JUnitVersion.JUnit5 - else -> { - throw IllegalArgumentException("JUnit version $jUnitVersion is not supported. Supported JUnit versions are '4' and '5'") - } - } - project.service().state.buildPath = classPath - - // Prepare Project Context - // First, get CUT Module - val cutModule = ProjectFileIndex.getInstance(project) - .getModuleForFile(targetPsiClass.containingFile.virtualFile) - // Then, instantiate the project context - val projectContext = ProjectContext( - classPath, - output, - targetPsiClass.qualifiedName, - cutModule, - ) - // Prepare the test generation data - val testGenerationData = TestGenerationData( - resultPath = output, - testResultName = "HeadlessGeneratedTests", - ) - println("[TestSpark Starter] Indexing is done") - - // get package name - val packageList = targetPsiClass.qualifiedName.toString().split(".").dropLast(1).toMutableList() - val packageName = packageList.joinToString(".") - - // Get PsiHelper - val psiHelper = PsiHelperProvider.getPsiHelper(psiFile) - if (psiHelper == null) { - // TODO exception: the support for the current language does not exist - } - // Create a process Manager - val llmProcessManager = Llm() - .getLLMProcessManager( - project, - psiHelper!!, - targetPsiClass.textRange.startOffset, - testSamplesCode = "", // we don't provide samples to LLM - projectSDKPath = projectSDKPath, - ) - - println("[TestSpark Starter] Starting the test generation process") - // Start test generation - val indicator = HeadlessProgressIndicator() - val errorMonitor = DefaultErrorMonitor() - val testCompiler = TestCompilerFactory.create( - project, - settingsState.junitVersion, - psiHelper.language, - projectSDKPath.toString(), - ) - val uiContext = llmProcessManager.runTestGenerator( - indicator, - FragmentToTestData(CodeType.CLASS), - packageName, - projectContext, - testGenerationData, - errorMonitor, - testsExecutionResultManager, - ) - - // Check test Generation Output - if (uiContext != null) { - println("[TestSpark Starter] Test generation completed successfully") - // Run test file - if (runCoverage) { - runTestsWithCoverageCollection( - project, - output, - packageList, - classPath, - projectContext, - projectSDKPath, - testCompiler, - settingsState.junitVersion, - ) - } - } else { - println("[TestSpark Starter] Test generation failed") - } - - ProjectManager.getInstance().closeAndDispose(project) - - println("[TestSpark Starter] Exiting the headless mode") - exitProcess(0) - } catch (e: Throwable) { - println("[TestSpark Starter] Exiting the headless mode with an exception") - - ProjectManager.getInstance().closeAndDispose(project) - e.printStackTrace(System.err) - exitProcess(0) - } - } - } - } - } - - /** - * Retrieves the project SDK based on the provided parameters. - * - * @param project the project inder test - * @return the project SDK for running and compiling tests generated in headless mode - */ - private fun getProjectSdkPath(project: Project): Path { - return when (val projectSdk = ProjectRootManager.getInstance(project).projectSdk) { - null -> { - println("Did not resolve the project SDK, using default SDK") - Paths.get(System.getProperty("java.home")) - } - - else -> Paths.get(projectSdk.homeDirectory!!.path) - } - } - - private fun runTestsWithCoverageCollection( - project: Project, - out: String, - packageList: MutableList, - classPath: String, - projectContext: ProjectContext, - projectSDKPath: Path, - testCompiler: TestCompiler, - junitVersion: JUnitVersion, - ) { - val targetDirectory = "$out${File.separator}${packageList.joinToString(File.separator)}" - println("Run tests in $targetDirectory") - File(targetDirectory).walk().forEach { - if (it.name.endsWith(".class")) { - println("Running test ${it.name}") - var testcaseName = it.nameWithoutExtension.removePrefix("Generated") - testcaseName = testcaseName[0].lowercaseChar() + testcaseName.substring(1) - // The current test is compiled and is ready to run jacoco - - val testExecutionError = TestProcessor(project, projectSDKPath).createXmlFromJacoco( - it.nameWithoutExtension, - "$targetDirectory${File.separator}jacoco-${it.nameWithoutExtension}", - testcaseName, - classPath, - packageList.joinToString("."), - out, - projectContext, - testCompiler, - junitVersion, - ) - // Saving exception (if exists) thrown during the test execution - saveException(testcaseName, targetDirectory, testExecutionError) - } - } - } - - private fun saveException( - testcaseName: String, - targetDirectory: String, - testExecutionError: String, - ) { - if (testExecutionError.isBlank() || !testExecutionError.contains("Exception", ignoreCase = false)) { - return - } - val targetPath = Paths.get(targetDirectory, "$testcaseName-exception.log") - - // Save the exception - targetPath.toFile().writeText(testExecutionError.replace("\tat ", "\nat ")) - } - - private fun detectPsiClass(classes: Array, classUnderTestName: String): PsiClass? { - for (psiClass in classes) { - if (psiClass.qualifiedName == classUnderTestName) { - return psiClass - } - } - return null - } -} diff --git a/src/main/kotlin/org/jetbrains/research/testspark/progress/HeadlessProgressIndicator.kt b/src/main/kotlin/org/jetbrains/research/testspark/progress/HeadlessProgressIndicator.kt deleted file mode 100644 index bea75791d..000000000 --- a/src/main/kotlin/org/jetbrains/research/testspark/progress/HeadlessProgressIndicator.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.jetbrains.research.testspark.progress - -import org.jetbrains.research.testspark.core.progress.CustomProgressIndicator - -/** - * A class that mocking the IDE progress indicator in headless environment. - * It implements the CustomProgressIndicator interface. - */ -class HeadlessProgressIndicator : CustomProgressIndicator { - override fun setText(text: String) {} - - override fun getText(): String = "" - - override fun setIndeterminate(value: Boolean) {} - - override fun isIndeterminate(): Boolean = false - - override fun setFraction(value: Double) {} - - override fun getFraction(): Double = 0.0 - - override fun cancel() {} - - override fun isCanceled(): Boolean = false - - override fun isRunning(): Boolean = true - - override fun start() {} - - override fun stop() {} -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d231b4cec..7c000bcc6 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -188,11 +188,6 @@ - -