diff --git a/.gitignore b/.gitignore
index aed022b20..8291da049 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/
diff --git a/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkAction.kt b/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkAction.kt
index 5f537ac89..e519ef8bd 100644
--- a/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkAction.kt
+++ b/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkAction.kt
@@ -1,53 +1,14 @@
package org.jetbrains.research.testspark.actions
-import com.intellij.notification.NotificationGroupManager
-import com.intellij.notification.NotificationType
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.project.Project
-import com.intellij.ui.components.JBScrollPane
-import com.intellij.util.ui.FormBuilder
import org.jetbrains.research.testspark.actions.controllers.TestGenerationController
import org.jetbrains.research.testspark.actions.controllers.VisibilityController
-import org.jetbrains.research.testspark.actions.evosuite.EvoSuitePanelBuilder
-import org.jetbrains.research.testspark.actions.llm.LLMSampleSelectorBuilder
-import org.jetbrains.research.testspark.actions.llm.LLMSetupPanelBuilder
-import org.jetbrains.research.testspark.actions.template.PanelBuilder
-import org.jetbrains.research.testspark.bundles.plugin.PluginLabelsBundle
-import org.jetbrains.research.testspark.bundles.plugin.PluginMessagesBundle
-import org.jetbrains.research.testspark.core.test.data.CodeType
import org.jetbrains.research.testspark.display.TestSparkDisplayManager
-import org.jetbrains.research.testspark.display.TestSparkIcons
-import org.jetbrains.research.testspark.langwrappers.PsiHelper
import org.jetbrains.research.testspark.langwrappers.PsiHelperProvider
-import org.jetbrains.research.testspark.services.EvoSuiteSettingsService
-import org.jetbrains.research.testspark.services.LLMSettingsService
-import org.jetbrains.research.testspark.settings.evosuite.EvoSuiteSettingsState
-import org.jetbrains.research.testspark.settings.llm.LLMSettingsState
import org.jetbrains.research.testspark.tools.TestsExecutionResultManager
-import org.jetbrains.research.testspark.tools.evosuite.EvoSuite
-import org.jetbrains.research.testspark.tools.kex.Kex
-import org.jetbrains.research.testspark.tools.llm.Llm
-import org.jetbrains.research.testspark.tools.template.Tool
-import java.awt.BorderLayout
-import java.awt.CardLayout
-import java.awt.Component
-import java.awt.Dimension
-import java.awt.Font
-import java.awt.Toolkit
-import java.awt.event.WindowAdapter
-import java.awt.event.WindowEvent
-import javax.swing.Box
-import javax.swing.BoxLayout
-import javax.swing.ButtonGroup
-import javax.swing.JButton
-import javax.swing.JFrame
-import javax.swing.JLabel
-import javax.swing.JPanel
-import javax.swing.JRadioButton
-import javax.swing.SwingConstants
/**
* Represents an action to be performed in the TestSpark plugin.
@@ -56,12 +17,6 @@ import javax.swing.SwingConstants
* It creates a dialog wrapper and displays it when the associated action is performed.
*/
class TestSparkAction : AnAction() {
- // Controllers
- private val visibilityController = VisibilityController()
- private val testGenerationController = TestGenerationController()
-
- private val testSparkDisplayManager = TestSparkDisplayManager()
- private val testsExecutionResultManager = TestsExecutionResultManager()
/**
* Handles the action performed event.
@@ -73,7 +28,13 @@ class TestSparkAction : AnAction() {
* This parameter is required.
*/
override fun actionPerformed(e: AnActionEvent) {
- TestSparkActionWindow(e, visibilityController, testGenerationController, testSparkDisplayManager, testsExecutionResultManager)
+ TestSparkActionWindow(
+ e = e,
+ visibilityController = VisibilityController(),
+ testGenerationController = TestGenerationController(),
+ testSparkDisplayManager = TestSparkDisplayManager(),
+ testsExecutionResultManager = TestsExecutionResultManager(),
+ )
}
/**
@@ -93,360 +54,5 @@ class TestSparkAction : AnAction() {
e.presentation.isEnabledAndVisible = (psiHelper != null) && psiHelper.availableForGeneration(e)
}
- /**
- * Class representing the TestSparkActionWindow.
- *
- * @property e The AnActionEvent object.
- */
- class TestSparkActionWindow(
- private val e: AnActionEvent,
- private val visibilityController: VisibilityController,
- private val testGenerationController: TestGenerationController,
- private val testSparkDisplayManager: TestSparkDisplayManager,
- private val testsExecutionResultManager: TestsExecutionResultManager,
- ) :
- JFrame("TestSpark") {
- private val project: Project = e.project!!
-
- private val llmSettingsState: LLMSettingsState
- get() = project.getService(LLMSettingsService::class.java).state
- private val evoSuiteSettingsState: EvoSuiteSettingsState
- get() = project.getService(EvoSuiteSettingsService::class.java).state
-
- private val llmButton = JRadioButton("${Llm().name}")
- private val evoSuiteButton = JRadioButton("${EvoSuite().name}")
- private val kexButton = JRadioButton("${Kex().name}")
- private val testGeneratorButtonGroup = ButtonGroup()
- private val kexForLineCodeTypeErrMsg = JLabel() // The error displayed when if kex and line code type are chosen
-
- private val psiHelper: PsiHelper
- get() {
- val file = e.dataContext.getData(CommonDataKeys.PSI_FILE)!!
- val psiHelper = PsiHelperProvider.getPsiHelper(file)
- if (psiHelper == null) {
- // TODO exception
- }
- return psiHelper!!
- }
-
- private val codeTypes = psiHelper.getCurrentListOfCodeTypes(e)
- private val caretOffset: Int = e.dataContext.getData(CommonDataKeys.CARET)?.caretModel?.primaryCaret!!.offset
- private val fileUrl = e.dataContext.getData(CommonDataKeys.VIRTUAL_FILE)!!.presentableUrl
-
- private val codeTypeButtons: MutableList> = mutableListOf()
- private val codeTypeButtonGroup = ButtonGroup()
-
- private val nextButton = JButton(PluginLabelsBundle.get("next"))
-
- private val cardLayout = CardLayout()
- private val llmSetupPanelFactory = LLMSetupPanelBuilder(e, project)
- private val llmSampleSelectorFactory = LLMSampleSelectorBuilder(project, psiHelper.language)
- private val evoSuitePanelFactory = EvoSuitePanelBuilder(project)
-
- init {
- if (!visibilityController.isVisible) {
- visibilityController.isVisible = true
- isVisible = true
-
- val panel = JPanel(cardLayout)
-
- panel.add(getMainPanel(), "1")
- panel.add(createCardPanel(evoSuitePanelFactory), "2")
- panel.add(createCardPanel(llmSetupPanelFactory), "3")
-
- panel.add(
- JBScrollPane(
- createCardPanel(llmSampleSelectorFactory),
- JBScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
- JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER,
- ),
- "4",
- )
-
- addListeners(panel)
-
- add(panel)
-
- pack()
-
- val dimension: Dimension = Toolkit.getDefaultToolkit().screenSize
- val x = (dimension.width - size.width) / 2
- val y = (dimension.height - size.height) / 2
- setLocation(x, y)
- } else {
- NotificationGroupManager.getInstance()
- .getNotificationGroup("Generation Error")
- .createNotification(
- PluginMessagesBundle.get("generationWindowWarningTitle"),
- PluginMessagesBundle.get("generationWindowWarningMessage"),
- NotificationType.WARNING,
- )
- .notify(e.project)
- }
- }
-
- private fun createCardPanel(toolPanelBuilder: PanelBuilder): JPanel {
- val cardPanel = JPanel(BorderLayout())
- cardPanel.add(toolPanelBuilder.getTitlePanel(), BorderLayout.NORTH)
- cardPanel.add(toolPanelBuilder.getMiddlePanel(), BorderLayout.CENTER)
- cardPanel.add(toolPanelBuilder.getBottomPanel(), BorderLayout.SOUTH)
-
- return cardPanel
- }
-
- /**
- * Returns the main panel for the test generator UI.
- * This panel contains options for selecting the test generator and the code type.
- * It also includes a button for proceeding to the next step.
- *
- * @return the main panel for the test generator UI
- */
- private fun getMainPanel(): JPanel {
- val panelTitle = JPanel()
- val textTitle = JLabel("Welcome to TestSpark!")
- textTitle.font = Font("Monochrome", Font.BOLD, 20)
- panelTitle.add(JLabel(TestSparkIcons.pluginIcon))
- panelTitle.add(textTitle)
-
- if (Llm().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(llmButton)
- if (EvoSuite().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(evoSuiteButton)
- if (Kex().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(kexButton)
-
- val testGeneratorPanel = JPanel()
- testGeneratorPanel.add(JLabel("Select the test generator:"))
- for (button in testGeneratorButtonGroup.elements) testGeneratorPanel.add(button)
- if (testGeneratorButtonGroup.elements.toList().size == 1) {
- // A single button is selected by default
- testGeneratorButtonGroup.elements.toList()[0].isSelected = true
- }
-
- for ((codeType, codeTypeName) in codeTypes) {
- val button = JRadioButton(codeTypeName)
- codeTypeButtons.add(codeType to button)
- codeTypeButtonGroup.add(button)
- }
-
- val codesToTestPanel = JPanel()
- codesToTestPanel.add(JLabel("Select the code type:"))
- if (codeTypeButtons.size == 1) {
- // A single button is selected by default
- codeTypeButtons[0].second.isSelected = true
- }
- for ((_, button) in codeTypeButtons) codesToTestPanel.add(button)
-
- val middlePanel = FormBuilder.createFormBuilder()
- .setFormLeftIndent(10)
- .addComponent(
- testGeneratorPanel,
- 10,
- )
- .addComponent(
- codesToTestPanel,
- 10,
- )
- .panel
-
- val nextButtonPanel = JPanel()
- nextButtonPanel.layout = BoxLayout(nextButtonPanel, BoxLayout.Y_AXIS)
- nextButton.isEnabled = false
- nextButton.alignmentX = Component.CENTER_ALIGNMENT
- kexForLineCodeTypeErrMsg.alignmentX = Component.CENTER_ALIGNMENT
- kexForLineCodeTypeErrMsg.horizontalAlignment = SwingConstants.CENTER
- nextButtonPanel.add(kexForLineCodeTypeErrMsg)
- nextButtonPanel.add(Box.createVerticalStrut(10)) // Add some space between label and button
- nextButtonPanel.add(nextButton)
- updateNextButton()
-
- val cardPanel = JPanel(BorderLayout())
- cardPanel.add(panelTitle, BorderLayout.NORTH)
- cardPanel.add(middlePanel, BorderLayout.CENTER)
- cardPanel.add(nextButtonPanel, BorderLayout.SOUTH)
-
- return cardPanel
- }
-
- /**
- * Adds listeners to various components in the given panel.
- *
- * @param panel the JPanel to add listeners to
- */
- private fun addListeners(panel: JPanel) {
- addWindowListener(object : WindowAdapter() {
- override fun windowClosing(e: WindowEvent?) {
- visibilityController.isVisible = false
- }
- })
-
- llmButton.addActionListener {
- updateNextButton()
- }
-
- evoSuiteButton.addActionListener {
- updateNextButton()
- }
-
- kexButton.addActionListener {
- updateNextButton()
- }
-
- for ((_, button) in codeTypeButtons) {
- button.addActionListener {
- llmSetupPanelFactory.setPromptEditorType(button.text)
- updateNextButton()
- }
- }
-
- nextButton.addActionListener {
- if (llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected && !llmSettingsState.provideTestSamplesCheckBoxSelected) {
- startLLMGeneration()
- } else if (llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected) {
- cardLayout.next(panel)
- cardLayout.next(panel)
- cardLayout.next(panel)
- pack()
- } else if (llmButton.isSelected) {
- cardLayout.next(panel)
- cardLayout.next(panel)
- pack()
- } else if (kexButton.isSelected) {
- startKexGeneration()
- } else if (evoSuiteButton.isSelected && !evoSuiteSettingsState.evosuiteSetupCheckBoxSelected) {
- startEvoSuiteGeneration()
- } else {
- cardLayout.next(panel)
- pack()
- }
- }
-
- evoSuitePanelFactory.getBackButton().addActionListener {
- cardLayout.previous(panel)
- pack()
- }
-
- llmSetupPanelFactory.getBackButton().addActionListener {
- cardLayout.previous(panel)
- cardLayout.previous(panel)
- pack()
- }
-
- llmSetupPanelFactory.getFinishedButton().addActionListener {
- llmSetupPanelFactory.applyUpdates()
- if (llmSettingsState.provideTestSamplesCheckBoxSelected) {
- cardLayout.next(panel)
- } else {
- startLLMGeneration()
- }
- }
-
- llmSampleSelectorFactory.getAddButton().addActionListener {
- size = Dimension(width, 500)
- }
-
- llmSampleSelectorFactory.getBackButton().addActionListener {
- if (llmSettingsState.llmSetupCheckBoxSelected) {
- cardLayout.previous(panel)
- } else {
- cardLayout.previous(panel)
- cardLayout.previous(panel)
- cardLayout.previous(panel)
- }
- pack()
- }
-
- llmSampleSelectorFactory.getFinishedButton().addActionListener {
- llmSampleSelectorFactory.applyUpdates()
- startLLMGeneration()
- }
-
- evoSuitePanelFactory.getFinishedButton().addActionListener {
- evoSuitePanelFactory.applyUpdates()
- startEvoSuiteGeneration()
- }
- }
-
- private fun startUnitTestGenerationTool(tool: Tool) {
- if (!testGenerationController.isGeneratorRunning(project)) {
- val testSamplesCode = llmSampleSelectorFactory.getTestSamplesCode()
-
- for ((codeType, button) in codeTypeButtons) {
- if (button.isSelected) {
- when (codeType) {
- CodeType.CLASS -> tool.generateTestsForClass(
- project,
- psiHelper,
- caretOffset,
- fileUrl,
- testSamplesCode,
- testGenerationController,
- testSparkDisplayManager,
- testsExecutionResultManager,
- )
- CodeType.METHOD -> tool.generateTestsForMethod(
- project,
- psiHelper,
- caretOffset,
- fileUrl,
- testSamplesCode,
- testGenerationController,
- testSparkDisplayManager,
- testsExecutionResultManager,
- )
- CodeType.LINE -> tool.generateTestsForLine(
- project,
- psiHelper,
- caretOffset,
- fileUrl,
- testSamplesCode,
- testGenerationController,
- testSparkDisplayManager,
- testsExecutionResultManager,
- )
- }
- break
- }
- }
- }
-
- visibilityController.isVisible = false
- dispose()
- }
-
- private fun startKexGeneration() = startUnitTestGenerationTool(tool = Kex())
- private fun startEvoSuiteGeneration() = startUnitTestGenerationTool(tool = EvoSuite())
- private fun startLLMGeneration() = startUnitTestGenerationTool(tool = Llm())
-
- /**
- * Updates the state of the "Next" button based on the selected options.
- * The "Next" button is enabled only if a test generator button (llmButton or evoSuiteButton) and at least one
- * code type button (from codeTypeButtons) are selected.
- *
- * This method should be called whenever the mentioned above buttons are clicked.
- */
- private fun updateNextButton() {
- val isTestGeneratorButtonGroupSelected = llmButton.isSelected || evoSuiteButton.isSelected || kexButton.isSelected
- val isCodeTypeButtonGroupSelected = codeTypeButtons.any { it.second.isSelected }
- val kexForCodeLineType =
- kexButton.isSelected && codeTypeButtons.any { (codeType, button) -> codeType == CodeType.LINE && button.isSelected }
- if (kexForCodeLineType) {
- kexForLineCodeTypeErrMsg.text =
- "* Kex cannot generate tests for a single line. Please change your selection"
- } else {
- kexForLineCodeTypeErrMsg.text = ""
- }
-
- nextButton.isEnabled =
- isTestGeneratorButtonGroupSelected && isCodeTypeButtonGroupSelected && !kexForCodeLineType
-
- if ((llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected && !llmSettingsState.provideTestSamplesCheckBoxSelected) ||
- (evoSuiteButton.isSelected && !evoSuiteSettingsState.evosuiteSetupCheckBoxSelected) ||
- kexButton.isSelected
- ) {
- nextButton.text = PluginLabelsBundle.get("ok")
- } else {
- nextButton.text = PluginLabelsBundle.get("next")
- }
- }
- }
-
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
}
diff --git a/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkActionWindow.kt b/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkActionWindow.kt
new file mode 100644
index 000000000..a8ca7ac08
--- /dev/null
+++ b/src/main/kotlin/org/jetbrains/research/testspark/actions/TestSparkActionWindow.kt
@@ -0,0 +1,402 @@
+package org.jetbrains.research.testspark.actions
+
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.project.Project
+import com.intellij.ui.components.JBScrollPane
+import com.intellij.util.ui.FormBuilder
+import org.jetbrains.research.testspark.actions.controllers.TestGenerationController
+import org.jetbrains.research.testspark.actions.controllers.VisibilityController
+import org.jetbrains.research.testspark.actions.evosuite.EvoSuitePanelBuilder
+import org.jetbrains.research.testspark.actions.llm.LLMSampleSelectorBuilder
+import org.jetbrains.research.testspark.actions.llm.LLMSetupPanelBuilder
+import org.jetbrains.research.testspark.actions.template.PanelBuilder
+import org.jetbrains.research.testspark.bundles.plugin.PluginLabelsBundle
+import org.jetbrains.research.testspark.bundles.plugin.PluginMessagesBundle
+import org.jetbrains.research.testspark.core.test.data.CodeType
+import org.jetbrains.research.testspark.display.TestSparkDisplayManager
+import org.jetbrains.research.testspark.display.TestSparkIcons
+import org.jetbrains.research.testspark.langwrappers.PsiHelper
+import org.jetbrains.research.testspark.langwrappers.PsiHelperProvider
+import org.jetbrains.research.testspark.services.EvoSuiteSettingsService
+import org.jetbrains.research.testspark.services.LLMSettingsService
+import org.jetbrains.research.testspark.settings.evosuite.EvoSuiteSettingsState
+import org.jetbrains.research.testspark.settings.llm.LLMSettingsState
+import org.jetbrains.research.testspark.tools.TestsExecutionResultManager
+import org.jetbrains.research.testspark.tools.evosuite.EvoSuite
+import org.jetbrains.research.testspark.tools.kex.Kex
+import org.jetbrains.research.testspark.tools.llm.Llm
+import org.jetbrains.research.testspark.tools.template.Tool
+import java.awt.BorderLayout
+import java.awt.CardLayout
+import java.awt.Dimension
+import java.awt.Font
+import java.awt.Toolkit
+import java.awt.event.WindowAdapter
+import java.awt.event.WindowEvent
+import javax.swing.Box
+import javax.swing.BoxLayout
+import javax.swing.ButtonGroup
+import javax.swing.JButton
+import javax.swing.JFrame
+import javax.swing.JLabel
+import javax.swing.JPanel
+import javax.swing.JRadioButton
+import javax.swing.SwingConstants
+
+/**
+ * Class representing the TestSparkActionWindow.
+ *
+ * @property e The AnActionEvent object.
+ */
+class TestSparkActionWindow(
+ private val e: AnActionEvent,
+ private val visibilityController: VisibilityController,
+ private val testGenerationController: TestGenerationController,
+ private val testSparkDisplayManager: TestSparkDisplayManager,
+ private val testsExecutionResultManager: TestsExecutionResultManager,
+) :
+ JFrame("TestSpark") {
+ private val project: Project = e.project!!
+
+ private val llmSettingsState: LLMSettingsState
+ get() = project.getService(LLMSettingsService::class.java).state
+ private val evoSuiteSettingsState: EvoSuiteSettingsState
+ get() = project.getService(EvoSuiteSettingsService::class.java).state
+
+ private val llmButton = JRadioButton("${Llm().name}")
+ private val evoSuiteButton = JRadioButton("${EvoSuite().name}")
+ private val kexButton = JRadioButton("${Kex().name}")
+ private val testGeneratorButtonGroup = ButtonGroup()
+ private val kexForLineCodeTypeErrMsg = JLabel() // The error displayed when if kex and line code type are chosen
+
+ private val psiHelper: PsiHelper
+ get() {
+ val file = e.dataContext.getData(CommonDataKeys.PSI_FILE)!!
+ val psiHelper = PsiHelperProvider.getPsiHelper(file)
+ return psiHelper!!
+ }
+
+ private val codeTypes = psiHelper.getCurrentListOfCodeTypes(e)
+ private val caretOffset: Int = e.dataContext.getData(CommonDataKeys.CARET)?.caretModel?.primaryCaret!!.offset
+ private val fileUrl = e.dataContext.getData(CommonDataKeys.VIRTUAL_FILE)!!.presentableUrl
+
+ private val codeTypeButtons: MutableList> = mutableListOf()
+ private val codeTypeButtonGroup = ButtonGroup()
+
+ private val nextButton = JButton(PluginLabelsBundle.get("next"))
+
+ private val cardLayout = CardLayout()
+ private val llmSetupPanelFactory = LLMSetupPanelBuilder(e, project)
+ private val llmSampleSelectorFactory = LLMSampleSelectorBuilder(project, psiHelper.language)
+ private val evoSuitePanelFactory = EvoSuitePanelBuilder(project)
+
+ init {
+ if (!visibilityController.isVisible) {
+ visibilityController.isVisible = true
+ isVisible = true
+
+ val panel = JPanel(cardLayout)
+
+ panel.add(getMainPanel(), "1")
+ panel.add(createCardPanel(evoSuitePanelFactory), "2")
+ panel.add(createCardPanel(llmSetupPanelFactory), "3")
+
+ panel.add(
+ JBScrollPane(
+ createCardPanel(llmSampleSelectorFactory),
+ JBScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JBScrollPane.HORIZONTAL_SCROLLBAR_NEVER,
+ ),
+ "4",
+ )
+
+ addListeners(panel)
+
+ add(panel)
+
+ pack()
+
+ val dimension: Dimension = Toolkit.getDefaultToolkit().screenSize
+ val x = (dimension.width - size.width) / 2
+ val y = (dimension.height - size.height) / 2
+ setLocation(x, y)
+ } else {
+ NotificationGroupManager.getInstance()
+ .getNotificationGroup("Generation Error")
+ .createNotification(
+ PluginMessagesBundle.get("generationWindowWarningTitle"),
+ PluginMessagesBundle.get("generationWindowWarningMessage"),
+ NotificationType.WARNING,
+ )
+ .notify(e.project)
+ }
+ }
+
+ private fun createCardPanel(toolPanelBuilder: PanelBuilder): JPanel {
+ val cardPanel = JPanel(BorderLayout())
+ cardPanel.add(toolPanelBuilder.getTitlePanel(), BorderLayout.NORTH)
+ cardPanel.add(toolPanelBuilder.getMiddlePanel(), BorderLayout.CENTER)
+ cardPanel.add(toolPanelBuilder.getBottomPanel(), BorderLayout.SOUTH)
+
+ return cardPanel
+ }
+
+ /**
+ * Returns the main panel for the test generator UI.
+ * This panel contains options for selecting the test generator and the code type.
+ * It also includes a button for proceeding to the next step.
+ *
+ * @return the main panel for the test generator UI
+ */
+ private fun getMainPanel(): JPanel {
+ val panelTitle = JPanel()
+ val textTitle = JLabel("Welcome to TestSpark!")
+ textTitle.font = Font("Monochrome", Font.BOLD, 20)
+ panelTitle.add(JLabel(TestSparkIcons.pluginIcon))
+ panelTitle.add(textTitle)
+
+ if (Llm().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(llmButton)
+ if (EvoSuite().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(evoSuiteButton)
+ if (Kex().appliedForLanguage(psiHelper.language)) testGeneratorButtonGroup.add(kexButton)
+
+ val testGeneratorPanel = JPanel()
+ testGeneratorPanel.add(JLabel("Select the test generator:"))
+ for (button in testGeneratorButtonGroup.elements) testGeneratorPanel.add(button)
+ if (testGeneratorButtonGroup.elements.toList().size == 1) {
+ // A single button is selected by default
+ testGeneratorButtonGroup.elements.toList()[0].isSelected = true
+ }
+
+ for ((codeType, codeTypeName) in codeTypes) {
+ val button = JRadioButton(codeTypeName)
+ codeTypeButtons.add(codeType to button)
+ codeTypeButtonGroup.add(button)
+ }
+
+ val codesToTestPanel = JPanel()
+ codesToTestPanel.add(JLabel("Select the code type:"))
+ if (codeTypeButtons.size == 1) {
+ // A single button is selected by default
+ codeTypeButtons[0].second.isSelected = true
+ }
+ for ((_, button) in codeTypeButtons) codesToTestPanel.add(button)
+
+ val middlePanel = FormBuilder.createFormBuilder()
+ .setFormLeftIndent(10)
+ .addComponent(
+ testGeneratorPanel,
+ 10,
+ )
+ .addComponent(
+ codesToTestPanel,
+ 10,
+ )
+ .panel
+
+ val nextButtonPanel = JPanel()
+ nextButtonPanel.layout = BoxLayout(nextButtonPanel, BoxLayout.Y_AXIS)
+ nextButton.isEnabled = false
+ nextButton.alignmentX = CENTER_ALIGNMENT
+ kexForLineCodeTypeErrMsg.alignmentX = CENTER_ALIGNMENT
+ kexForLineCodeTypeErrMsg.horizontalAlignment = SwingConstants.CENTER
+ nextButtonPanel.add(kexForLineCodeTypeErrMsg)
+ nextButtonPanel.add(Box.createVerticalStrut(10)) // Add some space between label and button
+ nextButtonPanel.add(nextButton)
+ updateNextButton()
+
+ val cardPanel = JPanel(BorderLayout())
+ cardPanel.add(panelTitle, BorderLayout.NORTH)
+ cardPanel.add(middlePanel, BorderLayout.CENTER)
+ cardPanel.add(nextButtonPanel, BorderLayout.SOUTH)
+
+ return cardPanel
+ }
+
+ /**
+ * Adds listeners to various components in the given panel.
+ *
+ * @param panel the JPanel to add listeners to
+ */
+ private fun addListeners(panel: JPanel) {
+ addWindowListener(object : WindowAdapter() {
+ override fun windowClosing(e: WindowEvent?) {
+ visibilityController.isVisible = false
+ }
+ })
+
+ llmButton.addActionListener {
+ updateNextButton()
+ }
+
+ evoSuiteButton.addActionListener {
+ updateNextButton()
+ }
+
+ kexButton.addActionListener {
+ updateNextButton()
+ }
+
+ for ((_, button) in codeTypeButtons) {
+ button.addActionListener {
+ llmSetupPanelFactory.setPromptEditorType(button.text)
+ updateNextButton()
+ }
+ }
+
+ nextButton.addActionListener {
+ if (llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected && !llmSettingsState.provideTestSamplesCheckBoxSelected) {
+ startLLMGeneration()
+ } else if (llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected) {
+ cardLayout.next(panel)
+ cardLayout.next(panel)
+ cardLayout.next(panel)
+ pack()
+ } else if (llmButton.isSelected) {
+ cardLayout.next(panel)
+ cardLayout.next(panel)
+ pack()
+ } else if (kexButton.isSelected) {
+ startKexGeneration()
+ } else if (evoSuiteButton.isSelected && !evoSuiteSettingsState.evosuiteSetupCheckBoxSelected) {
+ startEvoSuiteGeneration()
+ } else {
+ cardLayout.next(panel)
+ pack()
+ }
+ }
+
+ evoSuitePanelFactory.getBackButton().addActionListener {
+ cardLayout.previous(panel)
+ pack()
+ }
+
+ llmSetupPanelFactory.getBackButton().addActionListener {
+ cardLayout.previous(panel)
+ cardLayout.previous(panel)
+ pack()
+ }
+
+ llmSetupPanelFactory.getFinishedButton().addActionListener {
+ llmSetupPanelFactory.applyUpdates()
+ if (llmSettingsState.provideTestSamplesCheckBoxSelected) {
+ cardLayout.next(panel)
+ } else {
+ startLLMGeneration()
+ }
+ }
+
+ llmSampleSelectorFactory.getAddButton().addActionListener {
+ size = Dimension(width, 500)
+ }
+
+ llmSampleSelectorFactory.getBackButton().addActionListener {
+ if (llmSettingsState.llmSetupCheckBoxSelected) {
+ cardLayout.previous(panel)
+ } else {
+ cardLayout.previous(panel)
+ cardLayout.previous(panel)
+ cardLayout.previous(panel)
+ }
+ pack()
+ }
+
+ llmSampleSelectorFactory.getFinishedButton().addActionListener {
+ llmSampleSelectorFactory.applyUpdates()
+ startLLMGeneration()
+ }
+
+ evoSuitePanelFactory.getFinishedButton().addActionListener {
+ evoSuitePanelFactory.applyUpdates()
+ startEvoSuiteGeneration()
+ }
+ }
+
+ private fun startUnitTestGenerationTool(tool: Tool) {
+ if (!testGenerationController.isGeneratorRunning(project)) {
+ val testSamplesCode = llmSampleSelectorFactory.getTestSamplesCode()
+
+ for ((codeType, button) in codeTypeButtons) {
+ if (button.isSelected) {
+ when (codeType) {
+ CodeType.CLASS -> tool.generateTestsForClass(
+ project,
+ psiHelper,
+ caretOffset,
+ fileUrl,
+ testSamplesCode,
+ testGenerationController,
+ testSparkDisplayManager,
+ testsExecutionResultManager,
+ )
+
+ CodeType.METHOD -> tool.generateTestsForMethod(
+ project,
+ psiHelper,
+ caretOffset,
+ fileUrl,
+ testSamplesCode,
+ testGenerationController,
+ testSparkDisplayManager,
+ testsExecutionResultManager,
+ )
+
+ CodeType.LINE -> tool.generateTestsForLine(
+ project,
+ psiHelper,
+ caretOffset,
+ fileUrl,
+ testSamplesCode,
+ testGenerationController,
+ testSparkDisplayManager,
+ testsExecutionResultManager,
+ )
+ }
+ break
+ }
+ }
+ }
+
+ visibilityController.isVisible = false
+ dispose()
+ }
+
+ private fun startKexGeneration() = startUnitTestGenerationTool(tool = Kex())
+ private fun startEvoSuiteGeneration() = startUnitTestGenerationTool(tool = EvoSuite())
+ private fun startLLMGeneration() = startUnitTestGenerationTool(tool = Llm())
+
+ /**
+ * Updates the state of the "Next" button based on the selected options.
+ * The "Next" button is enabled only if a test generator button (llmButton or evoSuiteButton) and at least one
+ * code type button (from codeTypeButtons) are selected.
+ *
+ * This method should be called whenever the mentioned above buttons are clicked.
+ */
+ private fun updateNextButton() {
+ val isTestGeneratorButtonGroupSelected =
+ llmButton.isSelected || evoSuiteButton.isSelected || kexButton.isSelected
+ val isCodeTypeButtonGroupSelected = codeTypeButtons.any { it.second.isSelected }
+ val kexForCodeLineType =
+ kexButton.isSelected && codeTypeButtons.any { (codeType, button) -> codeType == CodeType.LINE && button.isSelected }
+ if (kexForCodeLineType) {
+ kexForLineCodeTypeErrMsg.text =
+ "* Kex cannot generate tests for a single line. Please change your selection"
+ } else {
+ kexForLineCodeTypeErrMsg.text = ""
+ }
+
+ nextButton.isEnabled =
+ isTestGeneratorButtonGroupSelected && isCodeTypeButtonGroupSelected && !kexForCodeLineType
+
+ if ((llmButton.isSelected && !llmSettingsState.llmSetupCheckBoxSelected && !llmSettingsState.provideTestSamplesCheckBoxSelected) ||
+ (evoSuiteButton.isSelected && !evoSuiteSettingsState.evosuiteSetupCheckBoxSelected) ||
+ kexButton.isSelected
+ ) {
+ nextButton.text = PluginLabelsBundle.get("ok")
+ } else {
+ nextButton.text = PluginLabelsBundle.get("next")
+ }
+ }
+}
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 025761b24..62a5d14ea 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
@@ -17,20 +17,17 @@ object TestCompilerFactory {
project: Project,
junitVersion: JUnitVersion,
language: SupportedLanguage,
- javaHomeDirectory: String? = null,
+ javaSDKHomePath: String = findJavaSDKHomePath(project)
): TestCompiler {
val libraryPaths = LibraryPathsProvider.getTestCompilationLibraryPaths()
val junitLibraryPaths = LibraryPathsProvider.getJUnitLibraryPaths(junitVersion)
- // TODO add the warning window that for Java we always need the javaHomeDirectoryPath
return when (language) {
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)
@@ -41,26 +38,16 @@ object TestCompilerFactory {
/**
* 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,
- ): String {
- val javaSDKHomePath =
- javaHomeDirectory
- ?: ProjectRootManager
- .getInstance(project)
- .projectSdk
- ?.homeDirectory
- ?.path
-
- if (javaSDKHomePath == null) {
- throw JavaSDKMissingException(LLMMessagesBundle.get("javaSdkNotConfigured"))
- }
- return javaSDKHomePath
+ private fun findJavaSDKHomePath(project: Project): String {
+ return ProjectRootManager
+ .getInstance(project)
+ .projectSdk
+ ?.homeDirectory
+ ?.path
+ ?: (throw JavaSDKMissingException(LLMMessagesBundle.get("javaSdkNotConfigured")))
}
}