diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.as32 b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.as32 new file mode 100644 index 00000000000..ffa6c40d6ce --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureKotlinTest.kt.as32 @@ -0,0 +1,265 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.configuration + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathMacros +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.ProjectJdkTable +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.util.io.FileUtilRt +import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess +import com.intellij.testFramework.PlatformTestCase +import com.intellij.testFramework.UsefulTestCase +import junit.framework.TestCase +import org.jetbrains.kotlin.idea.configuration.KotlinWithLibraryConfigurator.FileState +import org.jetbrains.kotlin.idea.framework.KotlinSdkType +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.utils.PathUtil +import java.io.File +import java.io.IOException + +abstract class AbstractConfigureKotlinTest : PlatformTestCase() { + override fun setUp() { + super.setUp() + + val distPaths = with(PathUtil.kotlinPathsForIdeaPlugin) { + listOf( + stdlibPath, + stdlibSourcesPath, + reflectPath, + kotlinTestPath, + jsKotlinTestJarPath, + jsStdLibJarPath, + jsStdLibSrcJarPath + ) + } + + for (path in distPaths) { + VfsRootAccess.allowRootAccess(testRootDisposable, path.absolutePath) + } + } + + @Throws(Exception::class) + override fun tearDown() { + PathMacros.getInstance().removeMacro(TEMP_DIR_MACRO_KEY) + + super.tearDown() + } + + @Throws(Exception::class) + override fun initApplication() { + super.initApplication() + + KotlinSdkType.setUpIfNeeded() + + ApplicationManager.getApplication().runWriteAction { + ProjectJdkTable.getInstance().addJdk(PluginTestCaseBase.mockJdk6()) + ProjectJdkTable.getInstance().addJdk(PluginTestCaseBase.mockJdk8()) + ProjectJdkTable.getInstance().addJdk(PluginTestCaseBase.mockJdk9()) + } + + PluginTestCaseBase.clearSdkTable(testRootDisposable) + + val tempLibDir = FileUtil.createTempDirectory("temp", null) + PathMacros.getInstance().setMacro(TEMP_DIR_MACRO_KEY, FileUtilRt.toSystemDependentName(tempLibDir.absolutePath)) + } + + protected fun doTestConfigureModulesWithNonDefaultSetup(configurator: KotlinWithLibraryConfigurator) { + assertNoFilesInDefaultPaths() + + val modules = modules + for (module in modules) { + assertNotConfigured(module, configurator) + } + + configurator.configure(myProject, emptyList()) + + assertNoFilesInDefaultPaths() + + for (module in modules) { + assertProperlyConfigured(module, configurator) + } + } + + protected fun doTestOneJavaModule(jarState: FileState) { + doTestOneModule(jarState, JAVA_CONFIGURATOR) + } + + protected fun doTestOneJsModule(jarState: FileState) { + doTestOneModule(jarState, JS_CONFIGURATOR) + } + + private fun doTestOneModule(jarState: FileState, configurator: KotlinWithLibraryConfigurator) { + val module = module + + assertNotConfigured(module, configurator) + configure(module, jarState, configurator) + assertProperlyConfigured(module, configurator) + } + + override fun getModule(): Module { + val modules = ModuleManager.getInstance(myProject).modules + assert(modules.size == 1) { "One module should be loaded " + modules.size } + myModule = modules[0] + return super.getModule() + } + + val modules: Array + get() = ModuleManager.getInstance(myProject).modules + + @Throws(IOException::class) + override fun getIprFile(): File { + val projectFilePath = projectRoot + "/projectFile.ipr" + TestCase.assertTrue("Project file should exists " + projectFilePath, File(projectFilePath).exists()) + return File(projectFilePath) + } + + @Throws(Exception::class) + override fun doCreateProject(projectFile: File): Project? { + return myProjectManager.loadProject(projectFile.path) + } + + private val projectName: String + get() { + val testName = getTestName(true) + return if (testName.contains("_")) { + testName.substring(0, testName.indexOf("_")) + } + else testName + } + + protected val projectRoot: String + get() = BASE_PATH + projectName + + override fun setUpModule() {} + + private fun assertNoFilesInDefaultPaths() { + UsefulTestCase.assertDoesntExist(File(JAVA_CONFIGURATOR.getDefaultPathToJarFile(project))) + UsefulTestCase.assertDoesntExist(File(JS_CONFIGURATOR.getDefaultPathToJarFile(project))) + } + + companion object { + private val BASE_PATH = "idea/testData/configuration/" + private val TEMP_DIR_MACRO_KEY = "TEMP_TEST_DIR" + protected val JAVA_CONFIGURATOR: KotlinJavaModuleConfigurator by lazy { + object : KotlinJavaModuleConfigurator() { + override fun getDefaultPathToJarFile(project: Project) = getPathRelativeToTemp("default_jvm_lib") + } + } + + protected val JS_CONFIGURATOR: KotlinJsModuleConfigurator by lazy { + object : KotlinJsModuleConfigurator() { + override fun getDefaultPathToJarFile(project: Project) = getPathRelativeToTemp("default_js_lib") + } + } + + private fun configure( + modules: List, + runtimeState: FileState, + configurator: KotlinWithLibraryConfigurator, + jarFromDist: String, + jarFromTemp: String + ) { + val project = modules.first().project + val collector = createConfigureKotlinNotificationCollector(project) + + val pathToJar = getPathToJar(runtimeState, jarFromDist, jarFromTemp) + for (module in modules) { + configurator.configureModule(module, pathToJar, pathToJar, collector, runtimeState) + } + collector.showNotification() + } + + private fun getPathToJar(runtimeState: FileState, jarFromDist: String, jarFromTemp: String) = when (runtimeState) { + KotlinWithLibraryConfigurator.FileState.EXISTS -> jarFromDist + KotlinWithLibraryConfigurator.FileState.COPY -> jarFromTemp + KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY -> jarFromDist + } + + protected fun configure(module: Module, jarState: FileState, configurator: KotlinProjectConfigurator) { + if (configurator is KotlinJavaModuleConfigurator) { + configure(listOf(module), jarState, + configurator as KotlinWithLibraryConfigurator, + pathToExistentRuntimeJar, pathToNonexistentRuntimeJar) + } + if (configurator is KotlinJsModuleConfigurator) { + configure(listOf(module), jarState, + configurator as KotlinWithLibraryConfigurator, + pathToExistentJsJar, pathToNonexistentJsJar) + } + } + + private val pathToNonexistentRuntimeJar: String + get() { + val pathToTempKotlinRuntimeJar = FileUtil.getTempDirectory() + "/kotlin-runtime.jar" + PlatformTestCase.myFilesToDelete.add(File(pathToTempKotlinRuntimeJar)) + return pathToTempKotlinRuntimeJar + } + + private val pathToNonexistentJsJar: String + get() { + val pathToTempKotlinRuntimeJar = FileUtil.getTempDirectory() + "/" + PathUtil.JS_LIB_JAR_NAME + PlatformTestCase.myFilesToDelete.add(File(pathToTempKotlinRuntimeJar)) + return pathToTempKotlinRuntimeJar + } + + private val pathToExistentRuntimeJar: String + get() = PathUtil.kotlinPathsForDistDirectory.stdlibPath.parent + + private val pathToExistentJsJar: String + get() = PathUtil.kotlinPathsForDistDirectory.jsStdLibJarPath.parent + + protected fun assertNotConfigured(module: Module, configurator: KotlinWithLibraryConfigurator) { + TestCase.assertFalse( + String.format("Module %s should not be configured as %s Module", module.name, configurator.presentableText), + configurator.isConfigured(module)) + } + + protected fun assertConfigured(module: Module, configurator: KotlinWithLibraryConfigurator) { + TestCase.assertTrue(String.format("Module %s should be configured with configurator '%s'", module.name, + configurator.presentableText), + configurator.isConfigured(module)) + } + + protected fun assertProperlyConfigured(module: Module, configurator: KotlinWithLibraryConfigurator) { + assertConfigured(module, configurator) + assertNotConfigured(module, getOppositeConfigurator(configurator)) + } + + private fun getOppositeConfigurator(configurator: KotlinWithLibraryConfigurator): KotlinWithLibraryConfigurator { + if (configurator === JAVA_CONFIGURATOR) return JS_CONFIGURATOR + if (configurator === JS_CONFIGURATOR) return JAVA_CONFIGURATOR + + throw IllegalArgumentException("Only JS_CONFIGURATOR and JAVA_CONFIGURATOR are supported") + } + + private fun getPathRelativeToTemp(relativePath: String): String { + val tempPath = PathMacros.getInstance().getValue(TEMP_DIR_MACRO_KEY) + return tempPath + '/' + relativePath + } + } + + override fun getTestProjectJdk(): Sdk { + val projectRootManager = ProjectRootManager.getInstance(project) + return projectRootManager.projectSdk ?: throw IllegalStateException("SDK ${projectRootManager.projectSdkName} was not found") + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt.as32 b/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt.as32 new file mode 100644 index 00000000000..981266c9fcf --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt.as32 @@ -0,0 +1,136 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.configuration + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.impl.ApplicationImpl +import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder +import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings +import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.junit.Assert +import java.io.File +import java.io.IOException + +open class ConfigureKotlinInTempDirTest : AbstractConfigureKotlinTest() { + @Throws(IOException::class) + override fun getIprFile(): File { + val tempDir = FileUtil.generateRandomTemporaryPath() + FileUtil.createTempDirectory("temp", null) + + FileUtil.copyDir(File(projectRoot), tempDir) + + val projectRoot = tempDir.path + + val projectFilePath = projectRoot + "/projectFile.ipr" + if (!File(projectFilePath).exists()) { + val dotIdeaPath = projectRoot + "/.idea" + Assert.assertTrue("Project file or '.idea' dir should exists in " + projectRoot, File(dotIdeaPath).exists()) + return File(projectRoot) + } + return File(projectFilePath) + } + + @Throws(IOException::class) + fun testNoKotlincExistsNoSettingsRuntime10() { + val application = ApplicationManager.getApplication() as ApplicationImpl + application.doNotSave(false) + Assert.assertEquals(LanguageVersion.KOTLIN_1_0, module.languageVersionSettings.languageVersion) + Assert.assertEquals(LanguageVersion.KOTLIN_1_0, myProject.getLanguageVersionSettings(null).languageVersion) + application.saveAll() + Assert.assertTrue(project.baseDir.findFileByRelativePath(".idea/kotlinc.xml") == null) + } + + fun testNoKotlincExistsNoSettingsLatestRuntime() { + val application = ApplicationManager.getApplication() as ApplicationImpl + application.doNotSave(false) + Assert.assertEquals(LanguageVersion.LATEST_STABLE, module.languageVersionSettings.languageVersion) + Assert.assertEquals(LanguageVersion.LATEST_STABLE, myProject.getLanguageVersionSettings(null).languageVersion) + application.saveAll() + Assert.assertTrue(project.baseDir.findFileByRelativePath(".idea/kotlinc.xml") == null) + } + + fun testKotlincExistsNoSettingsLatestRuntimeNoVersionAutoAdvance() { + val application = ApplicationManager.getApplication() as ApplicationImpl + application.doNotSave(false) + Assert.assertEquals(LanguageVersion.LATEST_STABLE, module.languageVersionSettings.languageVersion) + Assert.assertEquals(LanguageVersion.LATEST_STABLE, myProject.getLanguageVersionSettings(null).languageVersion) + KotlinCommonCompilerArgumentsHolder.getInstance(project).update { + autoAdvanceLanguageVersion = false + autoAdvanceApiVersion = false + } + application.saveAll() + Assert.assertTrue(project.baseDir.findFileByRelativePath(".idea/kotlinc.xml") != null) + } + + fun testDropKotlincOnVersionAutoAdvance() { + val application = ApplicationManager.getApplication() as ApplicationImpl + application.doNotSave(false) + Assert.assertEquals(LanguageVersion.LATEST_STABLE, module.languageVersionSettings.languageVersion) + KotlinCommonCompilerArgumentsHolder.getInstance(project).update { + autoAdvanceLanguageVersion = true + autoAdvanceApiVersion = true + } + application.saveAll() + Assert.assertTrue(project.baseDir.findFileByRelativePath(".idea/kotlinc.xml") == null) + } + + fun testProject106InconsistentVersionInConfig() { + val settings = KotlinFacetSettingsProvider.getInstance(myProject).getInitializedSettings(module) + Assert.assertEquals(false, settings.useProjectSettings) + Assert.assertEquals("1.0", settings.languageLevel!!.description) + Assert.assertEquals("1.0", settings.apiLevel!!.description) + } + + fun testProject107InconsistentVersionInConfig() { + val settings = KotlinFacetSettingsProvider.getInstance(myProject).getInitializedSettings(module) + Assert.assertEquals(false, settings.useProjectSettings) + Assert.assertEquals("1.0", settings.languageLevel!!.description) + Assert.assertEquals("1.0", settings.apiLevel!!.description) + } + + fun testFacetWithProjectSettings() { + val settings = KotlinFacetSettingsProvider.getInstance(myProject).getInitializedSettings(module) + Assert.assertEquals(true, settings.useProjectSettings) + Assert.assertEquals("1.1", settings.languageLevel!!.description) + Assert.assertEquals("1.1", settings.apiLevel!!.description) + Assert.assertEquals("-version -Xallow-kotlin-package -Xskip-metadata-version-check", settings.compilerSettings!!.additionalArguments) + } + + fun testLoadAndSaveProjectWithV2FacetConfig() { + val moduleFileContentBefore = String(module.moduleFile!!.contentsToByteArray()) + val application = ApplicationManager.getApplication() as ApplicationImpl + application.doNotSave(false) + application.saveAll() + val moduleFileContentAfter = String(module.moduleFile!!.contentsToByteArray()) + Assert.assertEquals(moduleFileContentBefore, moduleFileContentAfter) + } + + fun testApiVersionWithoutLanguageVersion() { + KotlinCommonCompilerArgumentsHolder.getInstance(myProject) + val settings = myProject.getLanguageVersionSettings() + Assert.assertEquals(ApiVersion.KOTLIN_1_1, settings.apiVersion) + } + + //todo[Sedunov]: wait for fix in platform to avoid misunderstood from Java newbies (also PluginStartupComponent) + /*fun testKotlinSdkAdded() { + Assert.assertTrue(ProjectJdkTable.getInstance().allJdks.any { it.sdkType is KotlinSdkType }) + }*/ +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.as32 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.as32 new file mode 100644 index 00000000000..3ed1638d936 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.as32 @@ -0,0 +1,417 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.jvm.JvmElement +import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.actions.* +import com.intellij.lang.jvm.types.JvmSubstitutor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Pair.pair +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiJvmSubstitutor +import com.intellij.psi.PsiSubstitutor +import com.intellij.psi.PsiType +import com.intellij.psi.codeStyle.SuggestedNameInfo +import com.intellij.testFramework.fixtures.CodeInsightTestFixture +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase +import org.jetbrains.kotlin.idea.search.allScope +import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.uast.UParameter +import org.jetbrains.uast.UastContext +import org.jetbrains.uast.toUElement +import org.junit.Assert + +class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() { + private class SimpleMethodRequest( + project: Project, + override val methodName: String, + override val modifiers: Collection = emptyList(), + override val returnType: ExpectedTypes = emptyList(), + override val annotations: Collection = emptyList(), + override val parameters: List = emptyList(), + override val targetSubstitutor: JvmSubstitutor = PsiJvmSubstitutor(project, PsiSubstitutor.EMPTY) + ) : CreateMethodRequest { + override val isValid: Boolean = true + } + + private class NameInfo(vararg names: String) : SuggestedNameInfo(names) + + override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK + + fun testMakeNotFinal() { + myFixture.configureByText("foo.kt", """ + class Foo { + fun bar(){} + } + """) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.FINAL, false) + ).findWithText("Make 'bar' open") + ) + myFixture.checkResult(""" + class Foo { + open fun bar(){} + } + """) + } + + fun testMakePrivate() { + myFixture.configureByText("foo.kt", """ + class Foo { + fun bar(){} + } + """) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PRIVATE, true) + ).findWithText("Make 'Foo' private") + ) + myFixture.checkResult(""" + private class Foo { + fun bar(){} + } + """) + } + + fun testMakeNotPrivate() { + myFixture.configureByText("foo.kt", """ + private class Foo { + fun bar(){} + } + """.trim()) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PRIVATE, false) + ).findWithText("Remove 'private' modifier") + ) + myFixture.checkResult(""" + class Foo { + fun bar(){} + } + """.trim(), true) + } + + fun testMakePrivatePublic() { + myFixture.configureByText( + "foo.kt", """class Foo { + | private fun bar(){} + |}""".trim().trimMargin() + ) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true) + ).findWithText("Remove 'private' modifier") + ) + myFixture.checkResult( + """class Foo { + | fun bar(){} + |}""".trim().trimMargin(), true + ) + } + + fun testMakeProtectedPublic() { + myFixture.configureByText( + "foo.kt", """open class Foo { + | protected fun bar(){} + |}""".trim().trimMargin() + ) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true) + ).findWithText("Remove 'protected' modifier") + ) + myFixture.checkResult( + """open class Foo { + | fun bar(){} + |}""".trim().trimMargin(), true + ) + } + + fun testMakeInternalPublic() { + myFixture.configureByText( + "foo.kt", """class Foo { + | internal fun bar(){} + |}""".trim().trimMargin() + ) + + myFixture.launchAction( + createModifierActions( + myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true) + ).findWithText("Remove 'internal' modifier") + ) + myFixture.checkResult( + """class Foo { + | fun bar(){} + |}""".trim().trimMargin(), true + ) + } + + fun testDontMakePublicPublic() { + myFixture.configureByText( + "foo.kt", """class Foo { + | fun bar(){} + |}""".trim().trimMargin() + ) + + assertEmpty(createModifierActions(myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.PUBLIC, true))) + } + + fun testDontMakeFunInObjectsOpen() { + myFixture.configureByText("foo.kt", """ + object Foo { + fun bar(){} + } + """.trim()) + assertEmpty(createModifierActions(myFixture.atCaret(), MemberRequest.Modifier(JvmModifier.FINAL, false))) + } + + fun testAddVoidVoidMethod() { + myFixture.configureByText("foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createMethodActions( + myFixture.atCaret(), + methodRequest(project, "baz", JvmModifier.PRIVATE, PsiType.VOID) + ).findWithText("Add method 'baz' to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo { + | fun bar() {} + | private fun baz() { + | + | } + |} + """.trim().trimMargin(), true) + } + + fun testAddIntIntMethod() { + myFixture.configureByText("foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createMethodActions( + myFixture.atCaret(), + SimpleMethodRequest(project, + methodName = "baz", + modifiers = listOf(JvmModifier.PUBLIC), + returnType = expectedTypes(PsiType.INT), + parameters = expectedParams(PsiType.INT)) + ).findWithText("Add method 'baz' to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo { + | fun bar() {} + | fun baz(param0: Int): Int { + | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + | } + |} + """.trim().trimMargin(), true) + } + + fun testAddIntPrimaryConstructor() { + myFixture.configureByText("foo.kt", """ + |class Foo { + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createConstructorActions( + myFixture.atCaret(), constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType))) + ).findWithText("Add primary constructor to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo(param0: Int) { + |} + """.trim().trimMargin(), true) + } + + fun testAddIntSecondaryConstructor() { + myFixture.configureByText("foo.kt", """ + |class Foo() { + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createConstructorActions( + myFixture.atCaret(), + constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType))) + ).findWithText("Add secondary constructor to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo() { + | constructor(param0: Int) { + | + | } + |} + """.trim().trimMargin(), true) + } + + fun testChangePrimaryConstructorInt() { + myFixture.configureByText("foo.kt", """ + |class Foo() { + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createConstructorActions( + myFixture.atCaret(), + constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType))) + ).findWithText("Add 'int' as 1st parameter to method 'Foo'") + ) + myFixture.checkResult(""" + |class Foo(param0: Int) { + |} + """.trim().trimMargin(), true) + } + + fun testRemoveConstructorParameters() { + myFixture.configureByText("foo.kt", """ + |class Foo(i: Int) { + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createConstructorActions( + myFixture.atCaret(), + constructorRequest(project, listOf(pair("param0", PsiType.INT as PsiType))) + ).findWithText("Remove 1st parameter from method 'Foo'") + ) + myFixture.checkResult(""" + |class Foo() { + |} + """.trim().trimMargin(), true) + } + + fun testAddStringVarProperty() { + myFixture.configureByText("foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createPropertyActions( + myFixture.atCaret(), + MemberRequest.Property( + propertyName = "baz", + visibilityModifier = JvmModifier.PUBLIC, + propertyType = PsiType.getTypeByName("java.lang.String", project, project.allScope()), + getterRequired = true, + setterRequired = true + ) + ).findWithText("Add 'var' property 'baz' to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo { + | var baz: String = TODO("initialize me") + | + | fun bar() {} + |} + """.trim().trimMargin(), true) + } + + fun testAddLateInitStringVarProperty() { + myFixture.configureByText("foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createPropertyActions( + myFixture.atCaret(), + MemberRequest.Property( + propertyName = "baz", + visibilityModifier = JvmModifier.PUBLIC, + propertyType = PsiType.getTypeByName("java.lang.String", project, project.allScope()), + getterRequired = true, + setterRequired = true + ) + ).findWithText("Add 'lateinit var' property 'baz' to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo { + | lateinit var baz: String + | + | fun bar() {} + |} + """.trim().trimMargin(), true) + } + + fun testAddStringValProperty() { + myFixture.configureByText("foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin()) + + myFixture.launchAction( + createPropertyActions( + myFixture.atCaret(), + MemberRequest.Property( + propertyName = "baz", + visibilityModifier = JvmModifier.PUBLIC, + propertyType = PsiType.getTypeByName("java.lang.String", project, project.allScope()), + getterRequired = true, + setterRequired = false + ) + ).findWithText("Add 'val' property 'baz' to 'Foo'") + ) + myFixture.checkResult(""" + |class Foo { + | val baz: String = TODO("initialize me") + | + | fun bar() {} + |} + """.trim().trimMargin(), true) + } + + private fun makeParams(vararg psyTypes: PsiType): List { + val uastContext = UastContext(myFixture.project) + val factory = JavaPsiFacade.getElementFactory(myFixture.project) + val parameters = psyTypes.mapIndexed { index, psiType -> factory.createParameter("param$index", psiType) } + return parameters.map { uastContext.convertElement(it, null, UParameter::class.java) as UParameter } + } + + private fun expectedTypes(vararg psiTypes: PsiType) = psiTypes.map { expectedType(it) } + + private fun expectedParams(vararg psyTypes: PsiType) = + psyTypes.mapIndexed { index, psiType -> NameInfo("param$index") to expectedTypes(psiType) } + + private inline fun CodeInsightTestFixture.atCaret() = elementAtCaret.toUElement() as T + + @Suppress("CAST_NEVER_SUCCEEDS") + private fun List.findWithText(text: String): IntentionAction = + this.firstOrNull { it.text == text } ?: + Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing +} +