diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/UTBotStartupActivity.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/UTBotStartupActivity.kt index 57b4e0ccd..ea71b006f 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/UTBotStartupActivity.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/UTBotStartupActivity.kt @@ -6,21 +6,21 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.startup.StartupActivity import org.utbot.cpp.clion.plugin.client.Client import org.utbot.cpp.clion.plugin.settings.UTBotPluginSpecificSettings +import org.utbot.cpp.clion.plugin.settings.pluginSettings +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.wizard.UTBotWizard import org.utbot.cpp.clion.plugin.utils.getClient import org.utbot.cpp.clion.plugin.utils.invokeOnEdt -import org.utbot.cpp.clion.plugin.utils.utbotSettings class UTBotStartupActivity : StartupActivity { override fun runActivity(project: Project) { - // start plugin and connect to server on project opening + project.getClient() guessPathsOnFirstProjectOpen(project) showWizardOnFirstProjectOpen(project) } private fun showWizardOnFirstProjectOpen(project: Project) { - val pluginSettings = service() if (pluginSettings.isFirstLaunch && !Client.IS_TEST_MODE) { pluginSettings.isFirstLaunch = false invokeOnEdt { @@ -31,7 +31,7 @@ class UTBotStartupActivity : StartupActivity { private fun guessPathsOnFirstProjectOpen(project: Project) { RunOnceUtil.runOnceForProject(project, "Guess UTBot paths in settings") { - project.utbotSettings.predictPaths() + project.settings.predictPaths() } } } \ No newline at end of file diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/Client.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/Client.kt index f54d8720e..17eb27b56 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/Client.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/Client.kt @@ -1,34 +1,28 @@ package org.utbot.cpp.clion.plugin.client import com.intellij.openapi.Disposable - -import testsgen.Testgen - import com.intellij.openapi.project.Project - +import io.grpc.Status +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch - -import io.grpc.Status -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout - -import kotlinx.coroutines.Job -import org.utbot.cpp.clion.plugin.grpc.getProjectConfigGrpcRequest -import org.utbot.cpp.clion.plugin.grpc.getVersionGrpcRequest import org.utbot.cpp.clion.plugin.client.requests.CheckProjectConfigurationRequest +import org.utbot.cpp.clion.plugin.grpc.getProjectConfigGrpcRequest import org.utbot.cpp.clion.plugin.listeners.ConnectionStatus import org.utbot.cpp.clion.plugin.listeners.UTBotEventsListener +import org.utbot.cpp.clion.plugin.settings.projectIndependentSettings import org.utbot.cpp.clion.plugin.utils.hasChildren import org.utbot.cpp.clion.plugin.utils.logger -import org.utbot.cpp.clion.plugin.utils.utbotSettings +import testsgen.Testgen /** * Sends requests to grpc server via stub @@ -38,13 +32,12 @@ class Client( clientId: String, private val loggingChannels: List ) : Disposable, - GrpcClient(project.utbotSettings.port, project.utbotSettings.serverName, clientId) { + GrpcClient(projectIndependentSettings.port, projectIndependentSettings.serverName, clientId) { var connectionStatus = ConnectionStatus.INIT private set private val messageBus = project.messageBus private var newClient = true - private val settings = project.utbotSettings private val logger = project.logger /* @@ -67,7 +60,7 @@ class Client( val servicesCS: CoroutineScope = CoroutineScope(dispatcher + excHandler + SupervisorJob()) init { - logger.info { "Connecting to server on host: ${settings.serverName} , port: ${settings.port}" } + logger.info { "Connecting to server on host: ${projectIndependentSettings.serverName} , port: ${projectIndependentSettings.port}" } startPeriodicHeartBeat() } @@ -92,18 +85,6 @@ class Client( fun isServerAvailable() = connectionStatus == ConnectionStatus.CONNECTED - fun doHandShake() { - requestsCS.launch { - // Logger.info("sending HandShake request!") - try { - stub.handshake(getVersionGrpcRequest()) - logger.info { "Handshake successful!" } - } catch (e: Exception) { - logger.warn { "HandShake failed with the following error: ${e.message}" } - } - } - } - private fun provideLoggingChannels() { for (channel in loggingChannels) { servicesCS.launch(CoroutineName(channel.toString())) { diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt index 7beb037c3..87f26e33c 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/client/handlers/ProjectConfigurationHandler.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.Flow import org.utbot.cpp.clion.plugin.UTBot import org.utbot.cpp.clion.plugin.actions.AskServerToGenerateBuildDir import org.utbot.cpp.clion.plugin.actions.AskServerToGenerateJsonForProjectConfiguration +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.utils.getClient import org.utbot.cpp.clion.plugin.utils.logger import org.utbot.cpp.clion.plugin.utils.notifyError @@ -13,7 +14,6 @@ import org.utbot.cpp.clion.plugin.utils.notifyInfo import org.utbot.cpp.clion.plugin.utils.notifyUnknownResponse import org.utbot.cpp.clion.plugin.utils.notifyWarning import org.utbot.cpp.clion.plugin.utils.refreshAndFindIOFile -import org.utbot.cpp.clion.plugin.utils.utbotSettings import testsgen.Testgen abstract class ProjectConfigResponseHandler( @@ -87,7 +87,7 @@ class CreateBuildDirHandler( } else -> notifyUnknownResponse(response, project) } - refreshAndFindIOFile(project.utbotSettings.buildDirPath.toString()) + refreshAndFindIOFile(project.settings.buildDirPath.toString()) } } @@ -106,6 +106,6 @@ class GenerateJsonHandler( ) else -> notifyUnknownResponse(response, project) } - refreshAndFindIOFile(project.utbotSettings.buildDirPath.toString()) + refreshAndFindIOFile(project.settings.buildDirPath.toString()) } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/ActionsGrpcRequests.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/ActionsGrpcRequests.kt index 8344575c8..fad3c7e5c 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/ActionsGrpcRequests.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/ActionsGrpcRequests.kt @@ -3,6 +3,7 @@ package org.utbot.cpp.clion.plugin.grpc import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.project.Project +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.utils.activeProject import org.utbot.cpp.clion.plugin.utils.convertToRemotePathIfNeeded import testsgen.Testgen @@ -88,13 +89,12 @@ private fun getPredicateGrpcRequest(predicate: String, returnValue: String, type .build() private fun getProjectGrpcRequest(project: Project): Testgen.ProjectRequest { - val settings = project.allSettings() return Testgen.ProjectRequest.newBuilder() .setSettingsContext(getSettingsContextMessage(project)) .setProjectContext(getProjectContextMessage(project)) - .setTargetPath(settings.convertedTargetPath) - .addAllSourcePaths(settings.convertedSourcePaths) - .setSynchronizeCode(settings.isRemoteScenario) + .setTargetPath(project.settings.convertedTargetPath) + .addAllSourcePaths(project.settings.convertedSourcePaths) + .setSynchronizeCode(project.settings.isRemoteScenario) .build() } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/GrpcMessagingUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/GrpcMessagingUtils.kt index 10ff347e2..dae7ad57c 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/GrpcMessagingUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/grpc/GrpcMessagingUtils.kt @@ -1,31 +1,29 @@ package org.utbot.cpp.clion.plugin.grpc -import com.intellij.openapi.components.service +import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.project.Project -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.settings import testsgen.Testgen fun getSettingsContextMessage(project: Project): Testgen.SettingsContext { - val settings = project.allSettings() + val storedSettings = project.settings.storedSettings return Testgen.SettingsContext.newBuilder() - .setVerbose(settings.verbose) - .setUseStubs(settings.useStubs) - .setTimeoutPerTest(settings.timeoutPerTest) - .setTimeoutPerFunction(settings.timeoutPerFunction) - .setGenerateForStaticFunctions(settings.generateForStaticFunctions) - .setUseDeterministicSearcher(settings.useDeterministicSearcher) + .setVerbose(storedSettings.verbose) + .setUseStubs(storedSettings.useStubs) + .setTimeoutPerTest(storedSettings.timeoutPerTest) + .setTimeoutPerFunction(storedSettings.timeoutPerFunction) + .setGenerateForStaticFunctions(storedSettings.generateForStaticFunctions) + .setUseDeterministicSearcher(storedSettings.useDeterministicSearcher) .build() } -fun getProjectContextMessage(project: Project): Testgen.ProjectContext { - val settings = project.allSettings() - return Testgen.ProjectContext.newBuilder() - .setProjectName(project.name) - .setProjectPath(settings.convertedProjectPath) - .setBuildDirRelativePath(settings.buildDirRelativePath) - .setResultsDirRelativePath("") // this path is used only by command line interface, server doesn't require it. - .setTestDirPath(settings.convertedTestDirPath) - .build() -} +fun getProjectContextMessage(project: Project): Testgen.ProjectContext = Testgen.ProjectContext.newBuilder() + .setProjectName(project.name) + .setProjectPath(project.settings.convertedProjectPath) + .setBuildDirRelativePath(project.settings.storedSettings.buildDirRelativePath) + .setResultsDirRelativePath("") // this path is used only by command line interface, server doesn't require it. + .setTestDirPath(project.settings.convertedTestDirPath) + .build() -fun Project.allSettings() = this.service() \ No newline at end of file +fun AnActionEvent.activeProject() = this.project + ?: error("A project related to action event $this not found") \ No newline at end of file diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/listeners/UTBotSettingsChangedListener.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/listeners/UTBotSettingsChangedListener.kt index 7ce0ac28c..6ccdd49f1 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/listeners/UTBotSettingsChangedListener.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/listeners/UTBotSettingsChangedListener.kt @@ -1,7 +1,7 @@ package org.utbot.cpp.clion.plugin.listeners import com.intellij.util.messages.Topic -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.UTBotAllProjectSettings fun interface UTBotSettingsChangedListener { companion object { @@ -11,5 +11,5 @@ fun interface UTBotSettingsChangedListener { ) } - fun settingsChanged(settings: UTBotAllSettings) + fun settingsChanged(settings: UTBotAllProjectSettings) } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/SettingsProvider.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/SettingsProvider.kt new file mode 100644 index 000000000..61f7f91ee --- /dev/null +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/SettingsProvider.kt @@ -0,0 +1,13 @@ +package org.utbot.cpp.clion.plugin.settings + +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project + +val Project.settings: UTBotAllProjectSettings + get() = this.service() + +val projectIndependentSettings: UTBotProjectIndependentSettings.State + get() = service().state + +val pluginSettings: UTBotPluginSpecificSettings + get() = service() \ No newline at end of file diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllProjectSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllProjectSettings.kt new file mode 100644 index 000000000..b0b9692bb --- /dev/null +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllProjectSettings.kt @@ -0,0 +1,91 @@ +package org.utbot.cpp.clion.plugin.settings + +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.guessProjectDir +import com.jetbrains.cidr.cpp.execution.CMakeAppRunConfiguration +import org.utbot.cpp.clion.plugin.listeners.UTBotSettingsChangedListener +import org.utbot.cpp.clion.plugin.ui.targetsToolWindow.UTBotTarget +import org.utbot.cpp.clion.plugin.utils.convertToRemotePathIfNeeded +import org.utbot.cpp.clion.plugin.utils.isWindows +import org.utbot.cpp.clion.plugin.utils.notifyWarning +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +@Service +class UTBotAllProjectSettings(val project: Project) { + val storedSettings: UTBotProjectStoredSettings.State + get() = project.service().state + + var projectPath: String + get() = storedSettings.projectPath ?: project.guessProjectDir()?.path + ?: error("Could not guess project path! Should be specified in settings by user") + set(value) { + storedSettings.projectPath = value + } + + val buildDirPath: Path + get() = Paths.get(projectPath).resolve(storedSettings.buildDirRelativePath) + + val convertedSourcePaths: List + get() = storedSettings.sourceDirs.map { it.convertToRemotePathIfNeeded(project) } + + val convertedTestDirPath: String + get() = storedSettings.testDirPath.convertToRemotePathIfNeeded(project) + + val convertedTargetPath: String + get() = if (storedSettings.targetPath == UTBotTarget.autoTarget.path) storedSettings.targetPath + else storedSettings.targetPath.convertToRemotePathIfNeeded(project) + + val convertedProjectPath: String get() = projectPath.convertToRemotePathIfNeeded(project) + + /** + * If this property returns true, plugin must convert path sent and returned from server. + * @see [String.convertToRemotePathIfNeeded], [String.convertFromRemotePathIfNeeded] + * + * If we are on Windows, this is not a server, so it is always a remote scenario. + */ + val isRemoteScenario: Boolean + get() { + val isLocalHost = projectIndependentSettings.serverName == "localhost" || projectIndependentSettings.serverName == "127.0.0.01" + return !(storedSettings.remotePath == projectPath && isLocalHost) || isWindows + } + + fun fireUTBotSettingsChanged() { + project.messageBus.syncPublisher(UTBotSettingsChangedListener.TOPIC).settingsChanged(this) + } + + fun predictPaths() { + fun getSourceFoldersFromSources(sources: Collection) = sources.map { it.parent }.toMutableSet() + + storedSettings.remotePath = projectPath + storedSettings.buildDirRelativePath = "build-utbot" + storedSettings.targetPath = UTBotTarget.autoTarget.path + + try { + storedSettings.testDirPath = Paths.get(projectPath, "tests").toString() + } catch (e: IllegalStateException) { + notifyWarning("Guessing settings failed: could not guess project path! Please specify project path in settings!") + } + + val cmakeRunConfiguration = CMakeAppRunConfiguration.getSelectedConfigurationAndTarget(project)?.first + val buildConfigurationSources = cmakeRunConfiguration?.cMakeTarget?.buildConfigurations?.map { it.sources } + //TODO: why do we use firstOrNull here? + val cmakeConfiguration = buildConfigurationSources?.firstOrNull() ?: emptySet() + + storedSettings.sourceDirs = getSourceFoldersFromSources(cmakeConfiguration) + } + + companion object { + const val clientVersion = "2022.7" + const val DEFAULT_HOST = "localhost" + const val DEFAULT_PORT = 2121 + } +} + +data class UTBotSettingsModel( + var projectSettings: UTBotProjectStoredSettings.State, + var globalSettings: UTBotProjectIndependentSettings.State, +) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllSettings.kt deleted file mode 100644 index 79e00e2e2..000000000 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotAllSettings.kt +++ /dev/null @@ -1,299 +0,0 @@ -package org.utbot.cpp.clion.plugin.settings - -import com.intellij.openapi.project.Project -import org.utbot.cpp.clion.plugin.ui.targetsToolWindow.UTBotTarget -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.Service -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage -import com.intellij.openapi.components.service -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.project.guessProjectDir -import com.jetbrains.cidr.cpp.execution.CMakeAppRunConfiguration -import org.utbot.cpp.clion.plugin.listeners.UTBotSettingsChangedListener -import org.utbot.cpp.clion.plugin.utils.convertToRemotePathIfNeeded -import org.utbot.cpp.clion.plugin.utils.isWindows -import org.utbot.cpp.clion.plugin.utils.notifyWarning -import java.io.File -import java.nio.file.Path -import java.nio.file.Paths - -/** - * Settings that are the same for all projects - */ -@Service -@State( - name = "UtBotGlobalSettings", - storages = [Storage("utbot-global-settings.xml")] -) -class UTBotGlobalSettings : PersistentStateComponent { - data class State( - var port: Int = UTBotAllSettings.DEFAULT_PORT, - var serverName: String = UTBotAllSettings.DEFAULT_HOST, - ) - - private var myState: State = State() - override fun getState(): State = myState - override fun loadState(state: State) { - myState = state - } -} - - -/** - * Settings that are specific to each project - */ -@Service -@State( - name = "UtBotSettings", - storages = [Storage("utbot-settings.xml")] -) -class UTBotProjectSettings(val project: Project) : PersistentStateComponent { - private var myState = State() - - // serialized by the ide - data class State( - var projectPath: String? = null, - var buildDirRelativePath: String = "build-utbot", - var testDirPath: String = "", - var targetPath: String = UTBotTarget.autoTarget.path, - var remotePath: String = "", - var sourceDirs: Set = setOf(), - var cmakeOptions: List = DEFAULT_CMAKE_OPTIONS, - var generateForStaticFunctions: Boolean = true, - var useStubs: Boolean = true, - var useDeterministicSearcher: Boolean = true, - var verbose: Boolean = false, - var timeoutPerFunction: Int = 0, - var timeoutPerTest: Int = 30 - ) - - override fun getState() = myState - - override fun loadState(state: State) { - myState = state - } - - companion object { - val DEFAULT_CMAKE_OPTIONS = listOf("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DCMAKE_EXPORT_LINK_COMMANDS=ON") - } -} - -data class UTBotSettingsModel( - var port: Int, - var serverName: String, - var projectPath: String, - var buildDirRelativePath: String, - var testDirPath: String, - var targetPath: String, - var remotePath: String, - var sourceDirs: Set, - var cmakeOptions: String, - var generateForStaticFunctions: Boolean, - var useStubs: Boolean, - var useDeterministicSearcher: Boolean, - var verbose: Boolean, - var timeoutPerFunction: Int, - var timeoutPerTest: Int -) - -@Service -class UTBotAllSettings(val project: Project) { - private val logger = Logger.getInstance(this::class.java) - private val projectSettings: UTBotProjectSettings.State get() = project.service().state - private val globalSettings: UTBotGlobalSettings.State get() = service().state - - var port: Int - get() = globalSettings.port - set(value) { - globalSettings.port = value - } - - var serverName: String - get() = globalSettings.serverName - set(value) { - globalSettings.serverName = value - } - - var projectPath: String - get() { - if (projectSettings.projectPath == null) { - projectSettings.projectPath = project.guessProjectDir()?.path - ?: error("Could not guess project path! Should be specified in settings by user") - } - return projectSettings.projectPath!! - } - set(value) { - projectSettings.projectPath = value - } - - var buildDirRelativePath: String - get() = projectSettings.buildDirRelativePath - set(value) { - projectSettings.buildDirRelativePath = value - } - - var testDirPath: String - get() = projectSettings.testDirPath - set(value) { - projectSettings.testDirPath = value - } - - var targetPath: String - get() = projectSettings.targetPath - set(value) { - projectSettings.targetPath = value - } - - var remotePath: String - get() = projectSettings.remotePath - set(value) { - projectSettings.remotePath = value - } - - var sourceDirs: Set - get() = projectSettings.sourceDirs - set(value) { - projectSettings.sourceDirs = value - } - - var cmakeOptions: String - get() = projectSettings.cmakeOptions.joinToString(" ") - set(value) { - projectSettings.cmakeOptions = value.split(" ") - } - - var generateForStaticFunctions: Boolean - get() = projectSettings.generateForStaticFunctions - set(value) { - projectSettings.generateForStaticFunctions = value - } - - var useStubs: Boolean - get() = projectSettings.useStubs - set(value) { - projectSettings.useStubs = value - } - - var useDeterministicSearcher: Boolean - get() = projectSettings.useDeterministicSearcher - set(value) { - projectSettings.useDeterministicSearcher = value - } - - var verbose: Boolean - get() = projectSettings.verbose - set(value) { - projectSettings.verbose = value - } - - var timeoutPerFunction: Int - get() = projectSettings.timeoutPerFunction - set(value) { - projectSettings.timeoutPerFunction = value - } - - var timeoutPerTest: Int - get() = projectSettings.timeoutPerTest - set(value) { - projectSettings.timeoutPerTest = value - } - - val convertedSourcePaths: List - get() = sourceDirs.map { it.convertToRemotePathIfNeeded(project) } - - val convertedTestDirPath: String - get() = testDirPath.convertToRemotePathIfNeeded(project) - - val convertedTargetPath: String - get() = if (targetPath == UTBotTarget.autoTarget.path) - targetPath - else targetPath.convertToRemotePathIfNeeded(project) - - val convertedProjectPath: String get() = projectPath.convertToRemotePathIfNeeded(project) - - private val isLocalHost: Boolean - get() = serverName == "localhost" || serverName == "127.0.0.1" - - /** - * If this property returns true, plugin must convert path sent and returned from server. - * @see [String.convertToRemotePathIfNeeded], [String.convertFromRemotePathIfNeeded] - * - * If we are on Windows, this is not a server, so it is always a remote scenario. - */ - val isRemoteScenario: Boolean - get() = !(remotePath == projectPath && isLocalHost) || isWindows - - fun predictPaths() { - logger.info("predict paths was called") - - fun getSourceFoldersFromSources(sources: Collection) = sources.map { - it.parent - }.toMutableSet() - - remotePath = projectPath - try { - testDirPath = Paths.get(projectPath, "tests").toString() - } catch (e: IllegalStateException) { - notifyWarning("Guessing settings failed: could not guess project path! Please specify project path in settings!") - } - buildDirRelativePath = "build-utbot" - targetPath = UTBotTarget.autoTarget.path - - val cmakeConfiguration = CMakeAppRunConfiguration.getSelectedConfigurationAndTarget(project) - ?.first?.cMakeTarget?.buildConfigurations?.first() - ?: return - - sourceDirs = getSourceFoldersFromSources(cmakeConfiguration.sources) - } - - val buildDirPath: Path - get() = Paths.get(projectPath).resolve(buildDirRelativePath) - - fun asModel() = UTBotSettingsModel( - port, - serverName, - projectPath, - buildDirRelativePath, - testDirPath, - targetPath, - remotePath, - sourceDirs, - cmakeOptions, - generateForStaticFunctions, - useStubs, - useDeterministicSearcher, - verbose, - timeoutPerFunction, - timeoutPerTest - ) - - fun applyModel(model: UTBotSettingsModel) { - port = model.port - serverName = model.serverName - projectPath = model.projectPath - buildDirRelativePath = model.buildDirRelativePath - testDirPath = model.testDirPath - targetPath = model.targetPath - remotePath = model.remotePath - sourceDirs = model.sourceDirs - cmakeOptions = model.cmakeOptions - generateForStaticFunctions = model.generateForStaticFunctions - useStubs = model.useStubs - useDeterministicSearcher = model.useDeterministicSearcher - verbose = model.verbose - timeoutPerFunction = model.timeoutPerFunction - timeoutPerTest = model.timeoutPerTest - } - - - fun fireUTBotSettingsChanged() { - project.messageBus.syncPublisher(UTBotSettingsChangedListener.TOPIC).settingsChanged(this) - } - - companion object { - const val clientVersion = "2022.7" - const val DEFAULT_HOST = "localhost" - const val DEFAULT_PORT = 2121 - } -} diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotConfigurable.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotConfigurable.kt index d5bd5dead..8fdce4605 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotConfigurable.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotConfigurable.kt @@ -1,6 +1,5 @@ package org.utbot.cpp.clion.plugin.settings -import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.options.BoundConfigurable @@ -25,10 +24,12 @@ import java.awt.Dimension class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( "Project Settings for Generating Tests" ) { - private val utbotSettings: UTBotAllSettings get() = myProject.service() private val logger = Logger.getInstance("ProjectConfigurable") private val panel by lazy { createMainPanel() } + private val settings: UTBotProjectStoredSettings.State + get() = myProject.settings.storedSettings + init { myProject.messageBus.connect() .subscribe(UTBotSettingsChangedListener.TOPIC, UTBotSettingsChangedListener { @@ -38,7 +39,7 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( override fun createPanel() = panel - fun Panel.createPathChooser(property: KMutableProperty0, name: String, chooserTitle: String): Row { + private fun Panel.createPathChooser(property: KMutableProperty0, name: String, chooserTitle: String): Row { return row(name) { textFieldWithBrowseButton( chooserTitle, @@ -53,15 +54,15 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( return panel { group("Connection Settings") { row(UTBot.message("settings.project.port")) { - intTextField().bindIntText(utbotSettings::port).applyToComponent { + intTextField().bindIntText(projectIndependentSettings::port).applyToComponent { maximumSize = TEXT_FIELD_MAX_SIZE } }.rowComment(UTBot.message("deployment.utbotPort.description")) row(UTBot.message("settings.project.serverName")) { - textField().bindText(utbotSettings::serverName) + textField().bindText(projectIndependentSettings::serverName) }.rowComment(UTBot.message("deployment.utbotHost.description")) row(UTBot.message("settings.project.remotePath")) { - textField().bindText(utbotSettings::remotePath).columns(COLUMNS_LARGE) + textField().bindText(settings::remotePath).columns(COLUMNS_LARGE) }.rowComment(UTBot.message("deployment.remotePath.description")) } @@ -72,22 +73,22 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( myProject, FileChooserDescriptorFactory.createSingleFileDescriptor() ).bindText( - getter = { utbotSettings.projectPath ?: "" }, - setter = { value -> utbotSettings.projectPath = value }) + getter = { myProject.settings.projectPath ?: "" }, + setter = { value -> myProject.settings.projectPath = value }) .columns(COLUMNS_LARGE) }.rowComment(UTBot.message("settings.project.projectPath.info")) createPathChooser( - utbotSettings::buildDirRelativePath, + settings::buildDirRelativePath, UTBot.message("settings.project.buildDir"), UTBot.message("settings.project.buildDir.browse.title") ).rowComment(UTBot.message("paths.buildDirectory.description")) createPathChooser( - utbotSettings::targetPath, + settings::targetPath, UTBot.message("settings.project.target"), UTBot.message("settings.project.target.browse.title") ).rowComment(UTBot.message("paths.target.description")) createPathChooser( - utbotSettings::testDirPath, + settings::testDirPath, UTBot.message("settings.project.testsDir"), UTBot.message("settings.project.testsDir.browse.title") ).rowComment(UTBot.message("paths.testsDirectory.description")) @@ -106,8 +107,8 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( row { label("Try to get paths from CMake model: ") button("Detect Paths") { - utbotSettings.predictPaths() - utbotSettings.fireUTBotSettingsChanged() + myProject.settings.predictPaths() + myProject.settings.fireUTBotSettingsChanged() } }.rowComment("Queries CMake configurations in order to get source paths, build path. Also predicts tests folder") } @@ -115,8 +116,8 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( group("CMake") { row(UTBot.message("settings.project.cmakeOptions")) { commandLineEditor( - { utbotSettings.cmakeOptions }, - { utbotSettings.cmakeOptions = it } + { settings.cmakeOptions }, + { settings.cmakeOptions = it } ) }.rowComment(UTBot.message("paths.cmakeOptions.description")) } @@ -136,22 +137,22 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( group("Generator settings") { val checkBoxes = listOf( CheckBoxInfo( - utbotSettings::useStubs, + settings::useStubs, UTBot.message("stubs.useStubs.title"), UTBot.message("stubs.useStubs.description") ), CheckBoxInfo( - utbotSettings::verbose, + settings::verbose, UTBot.message("testsGeneration.verboseFormatting.title"), UTBot.message("testsGeneration.verboseFormatting.description") ), CheckBoxInfo( - utbotSettings::useDeterministicSearcher, + settings::useDeterministicSearcher, UTBot.message("advanced.useDeterministicSearcher.title"), UTBot.message("advanced.useDeterministicSearcher.description") ), CheckBoxInfo( - utbotSettings::generateForStaticFunctions, + settings::generateForStaticFunctions, UTBot.message("testsGeneration.generateForStaticFunctions.title"), UTBot.message("testsGeneration.generateForStaticFunctions.description") ) @@ -161,13 +162,13 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( } row(UTBot.message("advanced.timeoutPerFunction.title")) { - intTextField().bindIntText(utbotSettings::timeoutPerFunction).applyToComponent { + intTextField().bindIntText(settings::timeoutPerFunction).applyToComponent { maximumSize = TEXT_FIELD_MAX_SIZE } }.rowComment(UTBot.message("advanced.timeoutPerFunction.description")) row(UTBot.message("advanced.timeoutPerTest.title")) { - intTextField().bindIntText(utbotSettings::timeoutPerFunction).applyToComponent { + intTextField().bindIntText(settings::timeoutPerFunction).applyToComponent { maximumSize = TEXT_FIELD_MAX_SIZE } }.rowComment(UTBot.message("advanced.timeoutPerTest.description")) @@ -182,7 +183,7 @@ class UTBotConfigurable(private val myProject: Project) : BoundConfigurable( override fun apply() { panel.apply() - utbotSettings.fireUTBotSettingsChanged() + myProject.settings.fireUTBotSettingsChanged() } override fun reset() { diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotPluginSpecificSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotPluginSpecificSettings.kt index 2150b8ef6..39ef35b9d 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotPluginSpecificSettings.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotPluginSpecificSettings.kt @@ -6,13 +6,9 @@ import com.intellij.openapi.components.Storage import com.intellij.util.xmlb.XmlSerializerUtil @State(name = "UTBotPluginSpecificSettings", storages = [Storage("UTBotPluginSpecificSettings.xml")]) -data class UTBotPluginSpecificSettings( - var isFirstLaunch: Boolean = true -) : PersistentStateComponent { - override fun getState(): UTBotPluginSpecificSettings { - return this - } +data class UTBotPluginSpecificSettings(var isFirstLaunch: Boolean = true) : PersistentStateComponent { + override fun getState(): UTBotPluginSpecificSettings = this override fun loadState(state: UTBotPluginSpecificSettings) { XmlSerializerUtil.copyBean(state, this); } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectIndependentSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectIndependentSettings.kt new file mode 100644 index 000000000..f82751f1a --- /dev/null +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectIndependentSettings.kt @@ -0,0 +1,32 @@ +package org.utbot.cpp.clion.plugin.settings + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage + +/** + * Settings that are the same for all projects + */ +@Service +@State( + name = "UtBotGlobalSettings", + storages = [Storage("utbot-global-settings.xml")] +) +class UTBotProjectIndependentSettings : PersistentStateComponent { + data class State( + var port: Int = UTBotAllProjectSettings.DEFAULT_PORT, + var serverName: String = UTBotAllProjectSettings.DEFAULT_HOST, + ) { + fun fromSettingsModel(model: UTBotSettingsModel) { + port = model.globalSettings.port + serverName = model.globalSettings.serverName + } + } + + private var myState: State = State() + override fun getState(): State = myState + override fun loadState(state: State) { + myState = state + } +} \ No newline at end of file diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectStoredSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectStoredSettings.kt new file mode 100644 index 000000000..011bfb4b4 --- /dev/null +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/settings/UTBotProjectStoredSettings.kt @@ -0,0 +1,61 @@ +package org.utbot.cpp.clion.plugin.settings + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.project.Project +import org.utbot.cpp.clion.plugin.ui.targetsToolWindow.UTBotTarget + +/** + * Settings that are specific to each project + */ +@Service +@State( + name = "UtBotSettings", + storages = [Storage("utbot-settings.xml")] +) +class UTBotProjectStoredSettings(val project: Project) : PersistentStateComponent { + private var myState = State() + + // serialized by the ide + data class State( + var projectPath: String? = null, + var buildDirRelativePath: String = "build-utbot", + var testDirPath: String = "", + var targetPath: String = UTBotTarget.autoTarget.path, + var remotePath: String = "", + var sourceDirs: Set = setOf(), + var cmakeOptions: String = DEFAULT_CMAKE_OPTIONS.joinToString(" "), + var generateForStaticFunctions: Boolean = true, + var useStubs: Boolean = true, + var useDeterministicSearcher: Boolean = true, + var verbose: Boolean = false, + var timeoutPerFunction: Int = 0, + var timeoutPerTest: Int = 30 + ) { + fun fromSettingsModel(model: UTBotSettingsModel) { + buildDirRelativePath = model.projectSettings.buildDirRelativePath + testDirPath = model.projectSettings.testDirPath + targetPath = model.projectSettings.targetPath + remotePath = model.projectSettings.remotePath + sourceDirs = model.projectSettings.sourceDirs + cmakeOptions = model.projectSettings.cmakeOptions + generateForStaticFunctions = model.projectSettings.generateForStaticFunctions + useStubs = model.projectSettings.useStubs + useDeterministicSearcher = model.projectSettings.useDeterministicSearcher + verbose = model.projectSettings.verbose + timeoutPerFunction = model.projectSettings.timeoutPerFunction + timeoutPerTest = model.projectSettings.timeoutPerTest + } + } + + override fun getState() = myState + override fun loadState(state: State) { + myState = state + } + + companion object { + val DEFAULT_CMAKE_OPTIONS = listOf("-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DCMAKE_EXPORT_LINK_COMMANDS=ON") + } +} \ No newline at end of file diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/ProxyProjectViewTree.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/ProxyProjectViewTree.kt index 1bd56e41f..9de5150f8 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/ProxyProjectViewTree.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/ProxyProjectViewTree.kt @@ -4,10 +4,10 @@ import com.intellij.ide.projectView.impl.ProjectViewTree import com.intellij.openapi.actionSystem.DataKey import com.intellij.openapi.actionSystem.DataProvider import com.intellij.openapi.project.Project -import javax.swing.tree.DefaultTreeModel -import org.utbot.cpp.clion.plugin.utils.utbotSettings +import org.utbot.cpp.clion.plugin.settings.settings import java.awt.event.MouseAdapter import java.awt.event.MouseEvent +import javax.swing.tree.DefaultTreeModel open class ProxyProjectViewTree( treeModel: DefaultTreeModel, @@ -33,9 +33,9 @@ open class ProxyProjectViewTree( } protected open fun createUpdater() = object : BaseUpdater(myPane.selectedDirectories.toList()) { - override fun getCurrentMarkedDirs(): Set = project.utbotSettings.sourceDirs + override fun getCurrentMarkedDirs(): Set = project.settings.storedSettings.sourceDirs override fun setCurrentMarkedDirs(value: Set) { - project.utbotSettings.sourceDirs = value.toMutableSet() + project.settings.storedSettings.sourceDirs = value.toMutableSet() } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPane.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPane.kt index 377b32535..a831aae97 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPane.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPane.kt @@ -7,9 +7,9 @@ import com.intellij.ide.projectView.impl.ProjectViewPane import com.intellij.ide.projectView.impl.ProjectViewTree import com.intellij.openapi.project.Project import com.intellij.psi.PsiFileSystemItem -import javax.swing.tree.DefaultTreeModel import org.utbot.cpp.clion.plugin.listeners.SourceFoldersListener -import org.utbot.cpp.clion.plugin.utils.utbotSettings +import org.utbot.cpp.clion.plugin.settings.settings +import javax.swing.tree.DefaultTreeModel open class UTBotProjectViewPane(project: Project) : ProjectViewPane(project) { override fun enableDnD() = Unit @@ -43,7 +43,7 @@ open class UTBotProjectViewPane(project: Project) : ProjectViewPane(project) { override fun createStructure() = object : AbstractProjectTreeStructure(myProject) { // replace directory nodes with our UTBotNodes, which check source dirs during node.update override fun getProviders() = listOf( - UTBotTreeStructureProvider(isMarked = { dir -> dir.virtualFile.path in myProject.utbotSettings.sourceDirs }) + UTBotTreeStructureProvider(isMarked = { dir -> dir.virtualFile.path in myProject.settings.storedSettings.sourceDirs }) ) } } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPaneForSettings.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPaneForSettings.kt index 3e1f6161b..683530026 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPaneForSettings.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/sourceFoldersView/UTBotProjectViewPaneForSettings.kt @@ -3,13 +3,17 @@ package org.utbot.cpp.clion.plugin.ui.sourceFoldersView import com.intellij.ide.projectView.impl.AbstractProjectTreeStructure import com.intellij.ide.projectView.impl.ProjectViewTree import com.intellij.openapi.project.Project -import javax.swing.tree.DefaultTreeModel +import org.utbot.cpp.clion.plugin.settings.UTBotProjectStoredSettings +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.wizard.steps.ObservableValue -import org.utbot.cpp.clion.plugin.utils.utbotSettings +import javax.swing.tree.DefaultTreeModel open class UTBotProjectViewPaneForSettings(project: Project) : UTBotProjectViewPane(project) { private val sourceDirs: ObservableValue> = initObservableDirectories() + private val settings: UTBotProjectStoredSettings.State + get() = myProject.settings.storedSettings + override fun createTree(treeModel: DefaultTreeModel): ProjectViewTree { return object : ProxyProjectViewTree(treeModel, myProject, this@UTBotProjectViewPaneForSettings) { override fun createUpdater(): BaseUpdater = object : BaseUpdater(selectedDirectories.toList()) { @@ -22,7 +26,7 @@ open class UTBotProjectViewPaneForSettings(project: Project) : UTBotProjectViewP } private fun initObservableDirectories(): ObservableValue> { - return ObservableValue(myProject.utbotSettings.sourceDirs).also { + return ObservableValue(settings.sourceDirs).also { it.addOnChangeListener { updateFromRoot(true) } @@ -30,14 +34,14 @@ open class UTBotProjectViewPaneForSettings(project: Project) : UTBotProjectViewP } fun apply() { - myProject.utbotSettings.sourceDirs = sourceDirs.value + settings.sourceDirs = sourceDirs.value } fun reset() { - sourceDirs.value = myProject.utbotSettings.sourceDirs + sourceDirs.value = settings.sourceDirs } - fun isModified() = myProject.utbotSettings.sourceDirs != sourceDirs.value + fun isModified() = settings.sourceDirs != sourceDirs.value override fun createStructure() = object : AbstractProjectTreeStructure(myProject) { override fun getProviders() = listOf(UTBotTreeStructureProvider(isMarked = { dir -> dir.virtualFile.path in sourceDirs.value})) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/statusBar/StatusBarVerboseMode.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/statusBar/StatusBarVerboseMode.kt index 7b93cd474..b6ae04724 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/statusBar/StatusBarVerboseMode.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/statusBar/StatusBarVerboseMode.kt @@ -6,7 +6,7 @@ import com.intellij.openapi.wm.StatusBarWidget import com.intellij.openapi.wm.StatusBarWidgetFactory import com.intellij.util.Consumer import org.utbot.cpp.clion.plugin.listeners.UTBotSettingsChangedListener -import org.utbot.cpp.clion.plugin.utils.utbotSettings +import org.utbot.cpp.clion.plugin.settings.settings import java.awt.Component import java.awt.event.MouseEvent @@ -51,7 +51,7 @@ class UTBotStatusBarVerboseWidget : StatusBarWidget, StatusBarWidget.TextPresent override fun getTooltipText() = VerboseModeWidgetFactory.STATUS_BAR_DISPLAY_NAME override fun getClickConsumer() = Consumer { _ -> - val settings = statusBar?.project!!.utbotSettings + val settings = statusBar?.project!!.settings.storedSettings settings.verbose = !settings.verbose statusBar?.updateWidget(ID()) } @@ -59,7 +59,7 @@ class UTBotStatusBarVerboseWidget : StatusBarWidget, StatusBarWidget.TextPresent override fun getText(): String { if (statusBar == null) return "" - return if (statusBar?.project!!.utbotSettings.verbose) "✔ UTBot: verbose formatting" else "❌ UTBot: verbose formatting" + return if (statusBar?.project!!.settings.storedSettings.verbose) "✔ UTBot: verbose formatting" else "❌ UTBot: verbose formatting" } override fun getAlignment(): Float = Component.CENTER_ALIGNMENT diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/targetsToolWindow/UTBotTargetsController.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/targetsToolWindow/UTBotTargetsController.kt index c7d7d314a..0811ddfb3 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/targetsToolWindow/UTBotTargetsController.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/targetsToolWindow/UTBotTargetsController.kt @@ -2,22 +2,24 @@ package org.utbot.cpp.clion.plugin.ui.targetsToolWindow import com.intellij.openapi.project.Project import com.intellij.ui.CollectionListModel -import org.utbot.cpp.clion.plugin.grpc.getProjectTargetsGrpcRequest import org.utbot.cpp.clion.plugin.client.Client import org.utbot.cpp.clion.plugin.client.requests.ProjectTargetsRequest +import org.utbot.cpp.clion.plugin.grpc.getProjectTargetsGrpcRequest import org.utbot.cpp.clion.plugin.listeners.ConnectionStatus import org.utbot.cpp.clion.plugin.listeners.UTBotEventsListener import org.utbot.cpp.clion.plugin.listeners.UTBotSettingsChangedListener -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.UTBotAllProjectSettings +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.utils.getClient import org.utbot.cpp.clion.plugin.utils.invokeOnEdt import org.utbot.cpp.clion.plugin.utils.logger import org.utbot.cpp.clion.plugin.utils.relativize -import org.utbot.cpp.clion.plugin.utils.utbotSettings class UTBotTargetsController(val project: Project) { - private val utbotSettings = project.utbotSettings - private val listModel = CollectionListModel(mutableListOf(UTBotTarget.autoTarget)) + private val settings: UTBotAllProjectSettings + get() = project.settings + + private val listModel = CollectionListModel(mutableListOf(UTBotTarget.autoTarget)) private val client: Client get() = project.getClient() private val logger = project.logger @@ -27,7 +29,7 @@ class UTBotTargetsController(val project: Project) { init { requestTargetsFromServer() - // addTargetPathIfNotPresent(utbotSettings.targetPath) + // addTargetPathIfNotPresent(settings.targetPath) connectToEvents() } @@ -62,7 +64,7 @@ class UTBotTargetsController(val project: Project) { UTBotTarget( possiblyNewTargetPath, "custom target", - relativize(utbotSettings.projectPath, possiblyNewTargetPath) + relativize(settings.projectPath, possiblyNewTargetPath) ) ) } @@ -74,12 +76,12 @@ class UTBotTargetsController(val project: Project) { fun selectionChanged(selectedTarget: UTBotTarget) { // when user selects target update model - utbotSettings.targetPath = selectedTarget.path + settings.storedSettings.targetPath = selectedTarget.path } fun setTargetByName(targetName: String) { val target = targets.find { it.name == targetName } ?: error("No such target!") - utbotSettings.targetPath = target.path + settings.storedSettings.targetPath = target.path } private fun connectToEvents() { @@ -87,8 +89,8 @@ class UTBotTargetsController(val project: Project) { // if user specifies some custom target path in settings, it will be added if not already present connection.subscribe( UTBotSettingsChangedListener.TOPIC, - UTBotSettingsChangedListener { settings: UTBotAllSettings -> - val possiblyNewTargetPath = settings.targetPath + UTBotSettingsChangedListener { + val possiblyNewTargetPath = settings.storedSettings.targetPath addTargetPathIfNotPresent(possiblyNewTargetPath) }) // when we reconnected to server, the targets should be updated, so we request them from server diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/UTBotWizard.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/UTBotWizard.kt index c8602671a..62e31e6c8 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/UTBotWizard.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/UTBotWizard.kt @@ -4,15 +4,17 @@ import com.intellij.ide.BrowserUtil import com.intellij.ide.wizard.AbstractWizard import com.intellij.openapi.project.Project import org.utbot.cpp.clion.plugin.UTBot +import org.utbot.cpp.clion.plugin.settings.UTBotSettingsModel +import org.utbot.cpp.clion.plugin.settings.projectIndependentSettings +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.wizard.steps.BuildOptionsStep import org.utbot.cpp.clion.plugin.ui.wizard.steps.ConnectionStep import org.utbot.cpp.clion.plugin.ui.wizard.steps.IntroStrep import org.utbot.cpp.clion.plugin.ui.wizard.steps.SuccessStep -import org.utbot.cpp.clion.plugin.utils.utbotSettings class UTBotWizard(private val project: Project) : AbstractWizard("UTBot: Quickstart", project) { // copy of settings to make changes during wizard steps - private val mySettingsModel = project.utbotSettings.asModel() + private val mySettingsModel = UTBotSettingsModel(project.settings.storedSettings, projectIndependentSettings) init { addStep(IntroStrep()) @@ -24,13 +26,18 @@ class UTBotWizard(private val project: Project) : AbstractWizard settingsModel.cmakeOptions = value }) + commandLineEditor({ settingsModel.projectSettings.cmakeOptions }, + { value: String -> settingsModel.projectSettings.cmakeOptions = value }) } }.addToUI() } diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/steps/ConnectionStep.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/steps/ConnectionStep.kt index 917130edd..768e6f492 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/steps/ConnectionStep.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/ui/wizard/steps/ConnectionStep.kt @@ -26,12 +26,12 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import org.utbot.cpp.clion.plugin.grpc.getVersionGrpcRequest import org.utbot.cpp.clion.plugin.client.GrpcClient -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.UTBotAllProjectSettings import org.utbot.cpp.clion.plugin.settings.UTBotSettingsModel +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.wizard.UTBotWizardStep import org.utbot.cpp.clion.plugin.utils.isWindows import org.utbot.cpp.clion.plugin.utils.toWSLPathOnWindows -import org.utbot.cpp.clion.plugin.utils.utbotSettings import org.utbot.cpp.clion.plugin.utils.validateOnInput class ObservableValue(initialValue: T) { @@ -100,9 +100,9 @@ class ConnectionStep( init { useDefaults.addOnChangeListener { newValue -> if (newValue) { - portTextField.text = UTBotAllSettings.DEFAULT_PORT.toString() - hostTextField.text = UTBotAllSettings.DEFAULT_HOST - remotePathTextField.text = project.utbotSettings.projectPath + portTextField.text = UTBotAllProjectSettings.DEFAULT_PORT.toString() + hostTextField.text = UTBotAllProjectSettings.DEFAULT_HOST + remotePathTextField.text = project.settings.projectPath if (isWindows) remotePathTextField.text = toWSLPathOnWindows(remotePathTextField.text) } @@ -114,7 +114,7 @@ class ConnectionStep( runCatching { GrpcClient(port, host, "DummyId").use { client -> serverVersion = client.stub.handshake(getVersionGrpcRequest()).version - if (serverVersion != UTBotAllSettings.clientVersion) + if (serverVersion != UTBotAllProjectSettings.clientVersion) return ConnectionStatus.warning return ConnectionStatus.connected } @@ -181,7 +181,7 @@ class ConnectionStep( row("Host") { textField().also { - it.bindText(settingsModel::serverName) + it.bindText(settingsModel.globalSettings::serverName) hostTextField = it.component }.columns(COLUMNS_MEDIUM).enabledIf(object : ComponentPredicate() { override fun invoke() = !useDefaults.value @@ -196,7 +196,7 @@ class ConnectionStep( 0..65535, 1 ).also { - it.bindIntText(settingsModel::port) + it.bindIntText(settingsModel.globalSettings::port) }.columns(COLUMNS_MEDIUM).applyToComponent { portTextField = this }.enabledIf(object : ComponentPredicate() { @@ -232,7 +232,7 @@ class ConnectionStep( val warningMessage: () -> String = { "⚠️ Warning! Versions are different" + if (serverVersion != null) - ": Server: $serverVersion Client: ${UTBotAllSettings.clientVersion}" + ": Server: $serverVersion Client: ${UTBotAllProjectSettings.clientVersion}" else "" } label(warningMessage()).visibleIf( @@ -257,7 +257,7 @@ class ConnectionStep( addHtml("media/remote_path.html") panel { row { - textField().bindText(settingsModel::remotePath).columns(COLUMNS_LARGE).applyToComponent { + textField().bindText(settingsModel.projectSettings::remotePath).columns(COLUMNS_LARGE).applyToComponent { remotePathTextField = this }.enabledIf(object : ComponentPredicate() { override fun invoke() = !useDefaults.value diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt index 504664d7c..24fe77b13 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/FileUtils.kt @@ -7,7 +7,7 @@ import com.intellij.util.io.createFile import kotlin.io.path.div import kotlin.io.path.writeText import org.apache.commons.io.FilenameUtils -import org.utbot.cpp.clion.plugin.grpc.allSettings +import org.utbot.cpp.clion.plugin.settings.settings import java.nio.file.FileVisitResult import java.nio.file.Files import java.nio.file.InvalidPathException @@ -104,8 +104,8 @@ private const val DOT_SEP = "_dot_" private const val TEST_SUFFIX = "_test" fun testFilePathToSourceFilePath(path: Path, project: Project): Path { - val relativeToProject = Paths.get(project.utbotSettings.testDirPath).relativize(path.parent) - return (Paths.get(project.utbotSettings.projectPath) / relativeToProject / testFileNameToSourceFileName(path)) + val relativeToProject = Paths.get(project.settings.storedSettings.testDirPath).relativize(path.parent) + return (Paths.get(project.settings.projectPath) / relativeToProject / testFileNameToSourceFileName(path)) } fun testFileNameToSourceFileName(path: Path): Path { @@ -154,14 +154,14 @@ fun toWSLPathOnWindows(filePath: String) = filePath * */ fun String.convertToRemotePathIfNeeded(project: Project): String { - if (project.allSettings().isRemoteScenario) + if (project.settings.isRemoteScenario) return this.convertToRemotePath(project) return this } private fun String.convertToRemotePath(project: Project): String { val relativeToProjectPath = this.getRelativeToProjectPath(project) - return FilenameUtils.separatorsToUnix(Paths.get(project.allSettings().remotePath, relativeToProjectPath).toString()) + return FilenameUtils.separatorsToUnix(Paths.get(project.settings.storedSettings.remotePath, relativeToProjectPath).toString()) } /** @@ -172,15 +172,14 @@ private fun String.convertToRemotePath(project: Project): String { * @param path - unix path absolute path from remote server to be converted */ fun String.convertFromRemotePathIfNeeded(project: Project): Path { - if (project.allSettings().isRemoteScenario) + if (project.settings.isRemoteScenario) return Paths.get(this.convertFromRemotePath(project)) return Paths.get(this) } private fun String.convertFromRemotePath(project: Project): String { - val settings = project.allSettings() - val relativeToProjectPath = FilenameUtils.separatorsToSystem(relativize(settings.remotePath, this)) - return FilenameUtils.separatorsToSystem(Paths.get(settings.projectPath, relativeToProjectPath).toString()) + val relativeToProjectPath = FilenameUtils.separatorsToSystem(relativize(project.settings.storedSettings.remotePath, this)) + return FilenameUtils.separatorsToSystem(Paths.get(project.settings.storedSettings.projectPath, relativeToProjectPath).toString()) } -private fun String.getRelativeToProjectPath(project: Project): String = relativize(project.allSettings().projectPath, this) +private fun String.getRelativeToProjectPath(project: Project): String = relativize(project.settings.projectPath, this) diff --git a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/shortcuts.kt b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/shortcuts.kt index bd8f4d9e3..dbfc008a6 100644 --- a/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/shortcuts.kt +++ b/clion-plugin/src/main/kotlin/org/utbot/cpp/clion/plugin/utils/shortcuts.kt @@ -10,19 +10,16 @@ import kotlinx.coroutines.job import org.utbot.cpp.clion.plugin.client.Client import org.utbot.cpp.clion.plugin.client.ClientManager import org.utbot.cpp.clion.plugin.client.logger.ClientLogger -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.UTBotAllProjectSettings val Project.logger: ClientLogger - get() = this.service() + get() = this.service() val AnActionEvent.client: Client get() = this.getRequiredData(CommonDataKeys.PROJECT).getClient() fun Project.getClient(): Client = this.service().client -val Project.utbotSettings: UTBotAllSettings - get() = this.service() - val CoroutineScope.children get() = this.coroutineContext.job.children.toList() diff --git a/clion-plugin/src/main/resources/META-INF/plugin.xml b/clion-plugin/src/main/resources/META-INF/plugin.xml index 1be41bda3..3f9feeccc 100644 --- a/clion-plugin/src/main/resources/META-INF/plugin.xml +++ b/clion-plugin/src/main/resources/META-INF/plugin.xml @@ -14,7 +14,7 @@ - + diff --git a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/BaseGenerationTestCase.kt b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/BaseGenerationTestCase.kt index d2a7d908a..f653800cb 100644 --- a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/BaseGenerationTestCase.kt +++ b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/BaseGenerationTestCase.kt @@ -8,7 +8,6 @@ import com.intellij.testFramework.fixtures.CodeInsightTestFixture import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl import com.intellij.util.io.delete -import kotlin.io.path.name import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterEach @@ -16,14 +15,14 @@ import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith import org.utbot.cpp.clion.plugin.client.Client import org.utbot.cpp.clion.plugin.client.logger.SystemWriter -import org.utbot.cpp.clion.plugin.settings.UTBotAllSettings +import org.utbot.cpp.clion.plugin.settings.settings import org.utbot.cpp.clion.plugin.ui.targetsToolWindow.UTBotTargetsController import org.utbot.cpp.clion.plugin.utils.getClient import org.utbot.cpp.clion.plugin.utils.logger -import org.utbot.cpp.clion.plugin.utils.utbotSettings import java.io.File import java.nio.file.Path import java.nio.file.Paths +import kotlin.io.path.name @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(SwingEdtInterceptor::class) @@ -59,15 +58,13 @@ abstract class BaseGenerationTestCase { val fixture: CodeInsightTestFixture = createFixture() val project: Project get() = fixture.project - val settings: UTBotAllSettings - get() = project.utbotSettings val client: Client get() = project.getClient() val targetsController = UTBotTargetsController(project) init { - settings.buildDirRelativePath = buildDirName - settings.testDirPath = testsDirectoryPath.toString() + project.settings.storedSettings.buildDirRelativePath = buildDirName + project.settings.storedSettings.testDirPath = testsDirectoryPath.toString() project.logger.writers.let { it.clear() it.add(SystemWriter()) @@ -114,7 +111,7 @@ abstract class BaseGenerationTestCase { @AfterEach fun tearDown() { logger.info("tearDown is called!") - project.utbotSettings.buildDirPath.delete(recursively = true) + project.settings.buildDirPath.delete(recursively = true) testsDirectoryPath.delete(recursively = true) } diff --git a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForFileTest.kt b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForFileTest.kt index 76f7e1c12..6d9f156bb 100644 --- a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForFileTest.kt +++ b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForFileTest.kt @@ -7,13 +7,14 @@ import org.utbot.cpp.clion.plugin.CppCompiler import org.utbot.cpp.clion.plugin.assertAllFilesNotEmptyRecursively import org.utbot.cpp.clion.plugin.assertFileOrDirExists import org.utbot.cpp.clion.plugin.assertTestFilesExist +import org.utbot.cpp.clion.plugin.settings.settings class GenerateForFileTest : BaseGenerationTestCase() { private val logger = setupLogger() fun doTest(relativeFilePath: String, compiler: CppCompiler, isVerboseMode: Boolean) { logger.info("Testing generate for file with file: $relativeFilePath, compiler: ${compiler.name}, verboseMode: $isVerboseMode") compiler.buildProject(projectPath, buildDirName) - settings.verbose = isVerboseMode + project.settings.storedSettings.verbose = isVerboseMode fixture.configureFromTempProjectFile(relativeFilePath) fixture.performEditorAction("com.huawei.utbot.cpp.actions.GenerateForFileAction") diff --git a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForIsolatedFileTest.kt b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForIsolatedFileTest.kt index dfe61efc9..21d7d9fec 100644 --- a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForIsolatedFileTest.kt +++ b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForIsolatedFileTest.kt @@ -6,13 +6,15 @@ import org.utbot.cpp.clion.plugin.Clang import org.utbot.cpp.clion.plugin.assertAllFilesNotEmptyRecursively import org.utbot.cpp.clion.plugin.assertFileOrDirExists import org.utbot.cpp.clion.plugin.assertTestFilesExist +import org.utbot.cpp.clion.plugin.settings.settings class GenerateForIsolatedFileTest : BaseGenerationTestCase() { private val logger = setupLogger() @Test fun testGenerateForFile() { val compiler = Clang - logger.info("Testing generate for snippet using target: auto, compiler: ${compiler.name}, verbose mode = ${settings.verbose}") + logger.info( + "Testing generate for snippet using target: auto, compiler: ${compiler.name}, verbose mode = ${project.settings.storedSettings.verbose}") compiler.buildProject(projectPath, buildDirName) fixture.configureFromTempProjectFile("snippet.c") fixture.performEditorAction("com.huawei.utbot.cpp.actions.GenerateForSnippetAction") diff --git a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForLineTest.kt b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForLineTest.kt index 1f4ba07c0..68de17ed0 100644 --- a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForLineTest.kt +++ b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForLineTest.kt @@ -9,6 +9,7 @@ import org.utbot.cpp.clion.plugin.Gcc import org.utbot.cpp.clion.plugin.assertAllFilesNotEmptyRecursively import org.utbot.cpp.clion.plugin.assertFileOrDirExists import org.utbot.cpp.clion.plugin.assertTestFilesExist +import org.utbot.cpp.clion.plugin.settings.settings class GenerateForLineTest: BaseGenerationTestCase() { private val logger = setupLogger() @@ -17,7 +18,7 @@ class GenerateForLineTest: BaseGenerationTestCase() { logger.info("Testing generate for line using target: $targetName, compiler: ${compiler.name}, verbose mode: $isVerbose, line: $lineNumber") compiler.buildProject(projectPath, buildDirName) setTarget(targetName) - settings.verbose = isVerbose + project.settings.storedSettings.verbose = isVerbose fixture.configureFromTempProjectFile("/lib/basic_functions.c") fixture.editor.moveCursorToLine(lineNumber) diff --git a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForProjectTest.kt b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForProjectTest.kt index ff4f8fb51..deb29cc88 100644 --- a/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForProjectTest.kt +++ b/clion-plugin/src/test/kotlin/org/utbot/cpp/clion/plugin/tests/GenerateForProjectTest.kt @@ -8,13 +8,14 @@ import org.utbot.cpp.clion.plugin.Gcc import org.utbot.cpp.clion.plugin.actions.generate.GenerateForProjectAction import org.utbot.cpp.clion.plugin.assertFileOrDirExists import org.utbot.cpp.clion.plugin.assertTestFilesExist +import org.utbot.cpp.clion.plugin.settings.settings class GenerateForProjectTest : BaseGenerationTestCase() { private val logger = setupLogger() private fun doTest(compiler: CppCompiler, isVerbose: Boolean, targetNames: List = emptyList()) { logger.info ( "Testing generate for project with ${compiler.name}, verbose mode: $isVerbose, and targets: ${targetNames.joinToString()}") - settings.verbose = isVerbose + project.settings.storedSettings.verbose = isVerbose compiler.buildProject(projectPath, buildDirName) for (targetName in targetNames) {