203: Fix compilation
This commit is contained in:
+1
-1
@@ -357,7 +357,7 @@ fun Task.listConfigurationContents(configName: String) {
|
||||
}
|
||||
|
||||
val defaultJvmTarget = "1.8"
|
||||
val defaultJavaHome = jdkPath(defaultJvmTarget)
|
||||
val defaultJavaHome = jdkPath(if (Platform[203].orHigher()) "11" else defaultJvmTarget)
|
||||
val ignoreTestFailures by extra(project.kotlinBuildProperties.ignoreTestFailures)
|
||||
|
||||
allprojects {
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||
package org.jetbrains.kotlin.codegen.inline.coroutines
|
||||
|
||||
import com.intellij.util.ArrayUtil
|
||||
|
||||
+5
-4
@@ -2,14 +2,16 @@
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||
package org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure
|
||||
|
||||
import io.ktor.network.sockets.Socket
|
||||
import kotlinx.coroutines.channels.*
|
||||
import io.ktor.network.sockets.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.*
|
||||
import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface
|
||||
import org.jetbrains.kotlin.daemon.common.experimental.LoopbackNetworkInterfaceKtor
|
||||
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.AnyMessage
|
||||
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.ServerDownMessage
|
||||
import sun.net.ConnectionResetException
|
||||
import java.beans.Transient
|
||||
import java.io.IOException
|
||||
@@ -17,7 +19,6 @@ import java.io.ObjectInputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.io.Serializable
|
||||
import java.util.logging.Logger
|
||||
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.Server.*
|
||||
|
||||
interface Client<ServerType : ServerBase> : Serializable, AutoCloseable {
|
||||
|
||||
|
||||
-1
@@ -44,7 +44,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.resolve.jvm.isInlineClassThatRequiresMangling
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
|
||||
import javax.rmi.CORBA.ClassDesc
|
||||
|
||||
class LocalFunInlineChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.psi.stubs.elements
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.psi.stubs.StubInputStream
|
||||
import com.intellij.psi.stubs.StubOutputStream
|
||||
import org.jetbrains.kotlin.psi.KtContractEffect
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinContractEffectStub
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinContractEffectStubImpl
|
||||
|
||||
class KtContractEffectElementType(debugName: String, psiClass: Class<KtContractEffect>) :
|
||||
KtStubElementType<KotlinContractEffectStub, KtContractEffect>(debugName, psiClass, KotlinContractEffectStub::class.java) {
|
||||
override fun serialize(stub: KotlinContractEffectStub, dataStream: StubOutputStream) {
|
||||
}
|
||||
|
||||
override fun deserialize(dataStream: StubInputStream, parentStub: StubElement<PsiElement>?): KotlinContractEffectStub {
|
||||
return KotlinContractEffectStubImpl(parentStub, this)
|
||||
}
|
||||
|
||||
override fun createStub(psi: KtContractEffect, parentStub: StubElement<*>?): KotlinContractEffectStub {
|
||||
return KotlinContractEffectStubImpl(parentStub, this)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.daemon.common.threadCpuTime
|
||||
|
||||
+1
-2
@@ -19,14 +19,13 @@ abstract public class KotlinCompletionTestCase extends CompletionTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory());
|
||||
CodeInsightSettings.getInstance().EXCLUDED_PACKAGES = new String[]{"excludedPackage", "somePackage.ExcludedClass"};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
CodeInsightSettings.getInstance().EXCLUDED_PACKAGES = ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch.ui
|
||||
|
||||
import com.intellij.core.JavaPsiBundle
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.openapi.actionSystem.Presentation
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.module.ModuleType
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.vcs.changes.committed.LabeledComboBoxAction
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.KotlinJvmBundle
|
||||
import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.testSourceInfo
|
||||
import org.jetbrains.kotlin.idea.scratch.ScratchFile
|
||||
import org.jetbrains.kotlin.idea.scratch.isKotlinWorksheet
|
||||
import java.util.function.Supplier
|
||||
import javax.swing.JComponent
|
||||
|
||||
class ModulesComboBoxAction(private val scratchFile: ScratchFile) :
|
||||
LabeledComboBoxAction(KotlinJvmBundle.message("scratch.module.combobox"))
|
||||
{
|
||||
override fun createPopupActionGroup(button: JComponent): DefaultActionGroup {
|
||||
val actionGroup = DefaultActionGroup()
|
||||
actionGroup.add(ModuleIsNotSelectedAction(JavaPsiBundle.messagePointer("list.item.no.module")))
|
||||
|
||||
val modules = ModuleManager.getInstance(scratchFile.project).modules.filter {
|
||||
it.productionSourceInfo() != null || it.testSourceInfo() != null
|
||||
}
|
||||
|
||||
actionGroup.addAll(modules.map { SelectModuleAction(it) })
|
||||
|
||||
return actionGroup
|
||||
}
|
||||
|
||||
/**
|
||||
* By default this action uses big font for label, so we have to decrease it
|
||||
* to make it look the same as in [CheckboxAction].
|
||||
*/
|
||||
override fun createCustomComponent(presentation: Presentation, place: String): JComponent {
|
||||
val customComponent = super.createCustomComponent(presentation, place)
|
||||
customComponent.components.forEach { it.font = UIUtil.getFont(UIUtil.FontSize.SMALL, it.font) }
|
||||
return customComponent
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
super.update(e)
|
||||
val selectedModule = scratchFile.module?.takeIf { !it.isDisposed }
|
||||
|
||||
e.presentation.apply {
|
||||
icon = selectedModule?.let { ModuleType.get(it).icon }
|
||||
text = selectedModule?.name ?: JavaPsiBundle.message("list.item.no.module")
|
||||
}
|
||||
|
||||
e.presentation.isVisible = isModuleSelectorVisible()
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun isModuleSelectorVisible(): Boolean {
|
||||
return !scratchFile.file.isKotlinWorksheet
|
||||
}
|
||||
|
||||
private inner class ModuleIsNotSelectedAction(placeholder: Supplier<String>) : DumbAwareAction(placeholder) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
scratchFile.setModule(null)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SelectModuleAction(private val module: Module) :
|
||||
DumbAwareAction(module.name, null, ModuleType.get(module).icon) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
scratchFile.setModule(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* 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.maven;
|
||||
|
||||
import com.intellij.compiler.server.BuildManager;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
|
||||
import com.intellij.openapi.roots.*;
|
||||
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.TestDialog;
|
||||
import com.intellij.openapi.util.AsyncResult;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.execution.MavenExecutor;
|
||||
import org.jetbrains.idea.maven.execution.MavenRunnerParameters;
|
||||
import org.jetbrains.idea.maven.execution.MavenRunnerSettings;
|
||||
import org.jetbrains.idea.maven.execution.SoutMavenConsole;
|
||||
import org.jetbrains.idea.maven.model.MavenArtifact;
|
||||
import org.jetbrains.idea.maven.model.MavenExplicitProfiles;
|
||||
import org.jetbrains.idea.maven.project.*;
|
||||
import org.jetbrains.jps.model.java.JavaResourceRootType;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType;
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
|
||||
import org.jetbrains.kotlin.idea.test.KotlinSdkCreationChecker;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@WithMutedInDatabaseRunTest
|
||||
public abstract class MavenImportingTestCase extends MavenTestCase {
|
||||
protected MavenProjectsTree myProjectsTree;
|
||||
protected MavenProjectsManager myProjectsManager;
|
||||
private File myGlobalSettingsFile;
|
||||
protected KotlinSdkCreationChecker sdkCreationChecker;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), PathManager.getConfigPath());
|
||||
super.setUp();
|
||||
myGlobalSettingsFile =
|
||||
MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().generalSettings.getEffectiveGlobalSettingsIoFile();
|
||||
if (myGlobalSettingsFile != null) {
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), myGlobalSettingsFile.getAbsolutePath());
|
||||
}
|
||||
sdkCreationChecker = new KotlinSdkCreationChecker();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUpInWriteAction() throws Exception {
|
||||
super.setUpInWriteAction();
|
||||
myProjectsManager = MavenProjectsManager.getInstance(myProject);
|
||||
removeFromLocalRepository("test");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
JavaAwareProjectJdkTableImpl.removeInternalJdkInTests();
|
||||
Messages.setTestDialog(TestDialog.DEFAULT);
|
||||
removeFromLocalRepository("test");
|
||||
FileUtil.delete(BuildManager.getInstance().getBuildSystemDirectory().toFile());
|
||||
sdkCreationChecker.removeNewKotlinSdk();
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTest() throws Throwable {
|
||||
KotlinTestUtils.runTestWithThrowable(this, () -> super.runTest());
|
||||
}
|
||||
|
||||
protected void assertModules(String... expectedNames) {
|
||||
Module[] actual = ModuleManager.getInstance(myProject).getModules();
|
||||
List<String> actualNames = new ArrayList<String>();
|
||||
|
||||
for (Module m : actual) {
|
||||
actualNames.add(m.getName());
|
||||
}
|
||||
|
||||
assertUnorderedElementsAreEqual(actualNames, expectedNames);
|
||||
}
|
||||
|
||||
protected void assertContentRoots(String moduleName, String... expectedRoots) {
|
||||
List<String> actual = new ArrayList<String>();
|
||||
for (ContentEntry e : getContentRoots(moduleName)) {
|
||||
actual.add(e.getUrl());
|
||||
}
|
||||
|
||||
for (int i = 0; i < expectedRoots.length; i++) {
|
||||
expectedRoots[i] = VfsUtil.pathToUrl(expectedRoots[i]);
|
||||
}
|
||||
|
||||
assertUnorderedPathsAreEqual(actual, Arrays.asList(expectedRoots));
|
||||
}
|
||||
|
||||
protected void assertSources(String moduleName, String... expectedSources) {
|
||||
assertContentFolders(moduleName, JavaSourceRootType.SOURCE, expectedSources);
|
||||
}
|
||||
|
||||
protected void assertGeneratedSources(String moduleName, String... expectedSources) {
|
||||
ContentEntry contentRoot = getContentRoot(moduleName);
|
||||
List<ContentFolder> folders = new ArrayList<ContentFolder>();
|
||||
for (SourceFolder folder : contentRoot.getSourceFolders(JavaSourceRootType.SOURCE)) {
|
||||
JavaSourceRootProperties properties = folder.getJpsElement().getProperties(JavaSourceRootType.SOURCE);
|
||||
assertNotNull(properties);
|
||||
if (properties.isForGeneratedSources()) {
|
||||
folders.add(folder);
|
||||
}
|
||||
}
|
||||
doAssertContentFolders(contentRoot, folders, expectedSources);
|
||||
}
|
||||
|
||||
protected void assertResources(String moduleName, String... expectedSources) {
|
||||
assertContentFolders(moduleName, JavaResourceRootType.RESOURCE, expectedSources);
|
||||
}
|
||||
|
||||
protected void assertTestSources(String moduleName, String... expectedSources) {
|
||||
assertContentFolders(moduleName, JavaSourceRootType.TEST_SOURCE, expectedSources);
|
||||
}
|
||||
|
||||
protected void assertTestResources(String moduleName, String... expectedSources) {
|
||||
assertContentFolders(moduleName, JavaResourceRootType.TEST_RESOURCE, expectedSources);
|
||||
}
|
||||
|
||||
protected void assertExcludes(String moduleName, String... expectedExcludes) {
|
||||
ContentEntry contentRoot = getContentRoot(moduleName);
|
||||
doAssertContentFolders(contentRoot, Arrays.asList(contentRoot.getExcludeFolders()), expectedExcludes);
|
||||
}
|
||||
|
||||
protected void assertContentRootExcludes(String moduleName, String contentRoot, String... expectedExcudes) {
|
||||
ContentEntry root = getContentRoot(moduleName, contentRoot);
|
||||
doAssertContentFolders(root, Arrays.asList(root.getExcludeFolders()), expectedExcudes);
|
||||
}
|
||||
|
||||
protected void assertContentFolders(String moduleName, @NotNull JpsModuleSourceRootType<?> rootType, String... expected) {
|
||||
ContentEntry contentRoot = getContentRoot(moduleName);
|
||||
doAssertContentFolders(contentRoot, contentRoot.getSourceFolders(rootType), expected);
|
||||
}
|
||||
|
||||
private static void doAssertContentFolders(ContentEntry e, final List<? extends ContentFolder> folders, String... expected) {
|
||||
List<String> actual = new ArrayList<String>();
|
||||
for (ContentFolder f : folders) {
|
||||
String rootUrl = e.getUrl();
|
||||
String folderUrl = f.getUrl();
|
||||
|
||||
if (folderUrl.startsWith(rootUrl)) {
|
||||
int length = rootUrl.length() + 1;
|
||||
folderUrl = folderUrl.substring(Math.min(length, folderUrl.length()));
|
||||
}
|
||||
|
||||
actual.add(folderUrl);
|
||||
}
|
||||
|
||||
assertOrderedElementsAreEqual(actual, Arrays.asList(expected));
|
||||
}
|
||||
|
||||
protected void assertModuleOutput(String moduleName, String output, String testOutput) {
|
||||
CompilerModuleExtension e = getCompilerExtension(moduleName);
|
||||
|
||||
assertFalse(e.isCompilerOutputPathInherited());
|
||||
assertEquals(output, getAbsolutePath(e.getCompilerOutputUrl()));
|
||||
assertEquals(testOutput, getAbsolutePath(e.getCompilerOutputUrlForTests()));
|
||||
}
|
||||
|
||||
private static String getAbsolutePath(String path) {
|
||||
path = VfsUtil.urlToPath(path);
|
||||
path = PathUtil.getCanonicalPath(path);
|
||||
return FileUtil.toSystemIndependentName(path);
|
||||
}
|
||||
|
||||
protected void assertProjectOutput(String module) {
|
||||
assertTrue(getCompilerExtension(module).isCompilerOutputPathInherited());
|
||||
}
|
||||
|
||||
protected CompilerModuleExtension getCompilerExtension(String module) {
|
||||
ModuleRootManager m = getRootManager(module);
|
||||
return CompilerModuleExtension.getInstance(m.getModule());
|
||||
}
|
||||
|
||||
protected void assertModuleLibDep(String moduleName, String depName) {
|
||||
assertModuleLibDep(moduleName, depName, null);
|
||||
}
|
||||
|
||||
protected void assertModuleLibDep(String moduleName, String depName, String classesPath) {
|
||||
assertModuleLibDep(moduleName, depName, classesPath, null, null);
|
||||
}
|
||||
|
||||
protected void assertModuleLibDep(String moduleName, String depName, String classesPath, String sourcePath, String javadocPath) {
|
||||
LibraryOrderEntry lib = getModuleLibDep(moduleName, depName);
|
||||
|
||||
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPath == null ? null : Collections.singletonList(classesPath));
|
||||
assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePath == null ? null : Collections.singletonList(sourcePath));
|
||||
assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(),
|
||||
javadocPath == null ? null : Collections.singletonList(javadocPath));
|
||||
}
|
||||
|
||||
protected void assertModuleLibDep(
|
||||
String moduleName,
|
||||
String depName,
|
||||
List<String> classesPaths,
|
||||
List<String> sourcePaths,
|
||||
List<String> javadocPaths
|
||||
) {
|
||||
LibraryOrderEntry lib = getModuleLibDep(moduleName, depName);
|
||||
|
||||
assertModuleLibDepPath(lib, OrderRootType.CLASSES, classesPaths);
|
||||
assertModuleLibDepPath(lib, OrderRootType.SOURCES, sourcePaths);
|
||||
assertModuleLibDepPath(lib, JavadocOrderRootType.getInstance(), javadocPaths);
|
||||
}
|
||||
|
||||
private static void assertModuleLibDepPath(LibraryOrderEntry lib, OrderRootType type, List<String> paths) {
|
||||
if (paths == null) return;
|
||||
assertUnorderedPathsAreEqual(Arrays.asList(lib.getRootUrls(type)), paths);
|
||||
// also check the library because it may contain slight different set of urls (e.g. with duplicates)
|
||||
assertUnorderedPathsAreEqual(Arrays.asList(lib.getLibrary().getUrls(type)), paths);
|
||||
}
|
||||
|
||||
protected void assertModuleLibDepScope(String moduleName, String depName, DependencyScope scope) {
|
||||
LibraryOrderEntry dep = getModuleLibDep(moduleName, depName);
|
||||
assertEquals(scope, dep.getScope());
|
||||
}
|
||||
|
||||
private LibraryOrderEntry getModuleLibDep(String moduleName, String depName) {
|
||||
return getModuleDep(moduleName, depName, LibraryOrderEntry.class);
|
||||
}
|
||||
|
||||
protected void assertModuleLibDeps(String moduleName, String... expectedDeps) {
|
||||
assertModuleDeps(moduleName, LibraryOrderEntry.class, expectedDeps);
|
||||
}
|
||||
|
||||
protected void assertExportedDeps(String moduleName, String... expectedDeps) {
|
||||
final List<String> actual = new ArrayList<String>();
|
||||
|
||||
getRootManager(moduleName).orderEntries().withoutSdk().withoutModuleSourceEntries().exportedOnly()
|
||||
.process(new RootPolicy<Object>() {
|
||||
@Override
|
||||
public Object visitModuleOrderEntry(ModuleOrderEntry e, Object value) {
|
||||
actual.add(e.getModuleName());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLibraryOrderEntry(LibraryOrderEntry e, Object value) {
|
||||
actual.add(e.getLibraryName());
|
||||
return null;
|
||||
}
|
||||
}, null);
|
||||
|
||||
assertOrderedElementsAreEqual(actual, expectedDeps);
|
||||
}
|
||||
|
||||
protected void assertModuleModuleDeps(String moduleName, String... expectedDeps) {
|
||||
assertModuleDeps(moduleName, ModuleOrderEntry.class, expectedDeps);
|
||||
}
|
||||
|
||||
private void assertModuleDeps(String moduleName, Class clazz, String... expectedDeps) {
|
||||
assertOrderedElementsAreEqual(collectModuleDepsNames(moduleName, clazz), expectedDeps);
|
||||
}
|
||||
|
||||
protected void assertModuleModuleDepScope(String moduleName, String depName, DependencyScope scope) {
|
||||
ModuleOrderEntry dep = getModuleModuleDep(moduleName, depName);
|
||||
assertEquals(scope, dep.getScope());
|
||||
}
|
||||
|
||||
private ModuleOrderEntry getModuleModuleDep(String moduleName, String depName) {
|
||||
return getModuleDep(moduleName, depName, ModuleOrderEntry.class);
|
||||
}
|
||||
|
||||
private List<String> collectModuleDepsNames(String moduleName, Class clazz) {
|
||||
List<String> actual = new ArrayList<String>();
|
||||
|
||||
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
|
||||
if (clazz.isInstance(e)) {
|
||||
actual.add(e.getPresentableName());
|
||||
}
|
||||
}
|
||||
return actual;
|
||||
}
|
||||
|
||||
private <T> T getModuleDep(String moduleName, String depName, Class<T> clazz) {
|
||||
T dep = null;
|
||||
|
||||
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
|
||||
if (clazz.isInstance(e) && e.getPresentableName().equals(depName)) {
|
||||
dep = (T) e;
|
||||
}
|
||||
}
|
||||
assertNotNull("Dependency not found: " + depName
|
||||
+ "\namong: " + collectModuleDepsNames(moduleName, clazz),
|
||||
dep);
|
||||
return dep;
|
||||
}
|
||||
|
||||
public void assertProjectLibraries(String... expectedNames) {
|
||||
List<String> actualNames = new ArrayList<String>();
|
||||
for (Library each : ProjectLibraryTable.getInstance(myProject).getLibraries()) {
|
||||
String name = each.getName();
|
||||
actualNames.add(name == null ? "<unnamed>" : name);
|
||||
}
|
||||
assertUnorderedElementsAreEqual(actualNames, expectedNames);
|
||||
}
|
||||
|
||||
protected void assertModuleGroupPath(String moduleName, String... expected) {
|
||||
String[] path = ModuleManager.getInstance(myProject).getModuleGroupPath(getModule(moduleName));
|
||||
|
||||
if (expected.length == 0) {
|
||||
assertNull(path);
|
||||
}
|
||||
else {
|
||||
assertNotNull(path);
|
||||
assertOrderedElementsAreEqual(Arrays.asList(path), expected);
|
||||
}
|
||||
}
|
||||
|
||||
protected Module getModule(final String name) {
|
||||
AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
|
||||
try {
|
||||
Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
|
||||
assertNotNull("Module " + name + " not found", m);
|
||||
return m;
|
||||
}
|
||||
finally {
|
||||
accessToken.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private ContentEntry getContentRoot(String moduleName) {
|
||||
ContentEntry[] ee = getContentRoots(moduleName);
|
||||
List<String> roots = new ArrayList<String>();
|
||||
for (ContentEntry e : ee) {
|
||||
roots.add(e.getUrl());
|
||||
}
|
||||
|
||||
String message = "Several content roots found: [" + StringUtil.join(roots, ", ") + "]";
|
||||
assertEquals(message, 1, ee.length);
|
||||
|
||||
return ee[0];
|
||||
}
|
||||
|
||||
private ContentEntry getContentRoot(String moduleName, String path) {
|
||||
for (ContentEntry e : getContentRoots(moduleName)) {
|
||||
if (e.getUrl().equals(VfsUtil.pathToUrl(path))) return e;
|
||||
}
|
||||
throw new AssertionError("content root not found");
|
||||
}
|
||||
|
||||
public ContentEntry[] getContentRoots(String moduleName) {
|
||||
return getRootManager(moduleName).getContentEntries();
|
||||
}
|
||||
|
||||
private ModuleRootManager getRootManager(String module) {
|
||||
return ModuleRootManager.getInstance(getModule(module));
|
||||
}
|
||||
|
||||
protected void importProject(@NonNls String xml) throws IOException {
|
||||
createProjectPom(xml);
|
||||
importProject();
|
||||
}
|
||||
|
||||
protected void importProject() {
|
||||
importProjectWithProfiles();
|
||||
}
|
||||
|
||||
protected void importProjectWithProfiles(String... profiles) {
|
||||
doImportProjects(Collections.singletonList(myProjectPom), profiles);
|
||||
}
|
||||
|
||||
protected void importProjects(VirtualFile... files) {
|
||||
doImportProjects(Arrays.asList(files));
|
||||
}
|
||||
|
||||
private void doImportProjects(List<VirtualFile> files, String... profiles) {
|
||||
initProjectsManager(false);
|
||||
|
||||
readProjects(files, profiles);
|
||||
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myProjectsManager.waitForResolvingCompletion();
|
||||
myProjectsManager.scheduleImportInTests(files);
|
||||
myProjectsManager.importProjects();
|
||||
}
|
||||
});
|
||||
|
||||
for (MavenProject each : myProjectsTree.getProjects()) {
|
||||
if (each.hasReadingProblems()) {
|
||||
System.out.println(each + " has problems: " + each.getProblems());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void readProjects(List<VirtualFile> files, String... profiles) {
|
||||
myProjectsManager.resetManagedFilesAndProfilesInTests(files, new MavenExplicitProfiles(Arrays.asList(profiles)));
|
||||
waitForReadingCompletion();
|
||||
}
|
||||
|
||||
protected void updateProjectsAndImport(VirtualFile... files) {
|
||||
readProjects(files);
|
||||
myProjectsManager.performScheduledImportInTests();
|
||||
}
|
||||
|
||||
protected void initProjectsManager(boolean enableEventHandling) {
|
||||
myProjectsManager.initForTests();
|
||||
myProjectsTree = myProjectsManager.getProjectsTreeForTests();
|
||||
if (enableEventHandling) myProjectsManager.listenForExternalChanges();
|
||||
}
|
||||
|
||||
protected void scheduleResolveAll() {
|
||||
myProjectsManager.scheduleResolveAllInTests();
|
||||
}
|
||||
|
||||
protected void waitForReadingCompletion() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
myProjectsManager.waitForReadingCompletion();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void readProjects() {
|
||||
readProjects(myProjectsManager.getProjectsFiles());
|
||||
}
|
||||
|
||||
protected void readProjects(VirtualFile... files) {
|
||||
List<MavenProject> projects = new ArrayList<MavenProject>();
|
||||
for (VirtualFile each : files) {
|
||||
projects.add(myProjectsManager.findProject(each));
|
||||
}
|
||||
myProjectsManager.forceUpdateProjects(projects);
|
||||
waitForReadingCompletion();
|
||||
}
|
||||
|
||||
protected void resolveDependenciesAndImport() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myProjectsManager.waitForResolvingCompletion();
|
||||
myProjectsManager.performScheduledImportInTests();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void resolveFoldersAndImport() {
|
||||
myProjectsManager.scheduleFoldersResolveForAllProjects();
|
||||
myProjectsManager.waitForFoldersResolvingCompletion();
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myProjectsManager.performScheduledImportInTests();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void resolvePlugins() {
|
||||
myProjectsManager.waitForPluginsResolvingCompletion();
|
||||
}
|
||||
|
||||
protected void downloadArtifacts() {
|
||||
downloadArtifacts(myProjectsManager.getProjects(), null);
|
||||
}
|
||||
|
||||
protected MavenArtifactDownloader.DownloadResult downloadArtifacts(
|
||||
Collection<MavenProject> projects,
|
||||
List<MavenArtifact> artifacts
|
||||
) {
|
||||
final MavenArtifactDownloader.DownloadResult[] unresolved = new MavenArtifactDownloader.DownloadResult[1];
|
||||
|
||||
AsyncResult<MavenArtifactDownloader.DownloadResult> result = new AsyncResult<MavenArtifactDownloader.DownloadResult>();
|
||||
result.doWhenDone(new Consumer<MavenArtifactDownloader.DownloadResult>() {
|
||||
@Override
|
||||
public void consume(MavenArtifactDownloader.DownloadResult unresolvedArtifacts) {
|
||||
unresolved[0] = unresolvedArtifacts;
|
||||
}
|
||||
});
|
||||
|
||||
myProjectsManager.scheduleArtifactsDownloading(projects, artifacts, true, true, result);
|
||||
myProjectsManager.waitForArtifactsDownloadingCompletion();
|
||||
|
||||
return unresolved[0];
|
||||
}
|
||||
|
||||
protected void performPostImportTasks() {
|
||||
myProjectsManager.waitForPostImportTasksCompletion();
|
||||
}
|
||||
|
||||
protected void executeGoal(String relativePath, String goal) {
|
||||
VirtualFile dir = myProjectRoot.findFileByRelativePath(relativePath);
|
||||
|
||||
MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), Collections.<String>emptyList());
|
||||
MavenRunnerSettings rs = new MavenRunnerSettings();
|
||||
MavenExecutor e = new MavenExternalExecutor(myProject, rp, getMavenGeneralSettings(), rs, new SoutMavenConsole());
|
||||
|
||||
e.execute(new EmptyProgressIndicator());
|
||||
}
|
||||
|
||||
protected void removeFromLocalRepository(String relativePath) throws IOException {
|
||||
FileUtil.delete(new File(getRepositoryPath(), relativePath));
|
||||
}
|
||||
|
||||
protected void setupJdkForModules(String... moduleNames) {
|
||||
for (String each : moduleNames) {
|
||||
setupJdkForModule(each);
|
||||
}
|
||||
}
|
||||
|
||||
protected Sdk setupJdkForModule(final String moduleName) {
|
||||
final Sdk sdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
|
||||
ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk);
|
||||
return sdk;
|
||||
}
|
||||
|
||||
protected static Sdk createJdk(String versionName) {
|
||||
return IdeaTestUtil.getMockJdk17(versionName);
|
||||
}
|
||||
|
||||
protected static AtomicInteger configConfirmationForYesAnswer() {
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
Messages.setTestDialog(new TestDialog() {
|
||||
@Override
|
||||
public int show(String message) {
|
||||
counter.set(counter.get() + 1);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
return counter;
|
||||
}
|
||||
|
||||
protected static AtomicInteger configConfirmationForNoAnswer() {
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
Messages.setTestDialog(new TestDialog() {
|
||||
@Override
|
||||
public int show(String message) {
|
||||
counter.set(counter.get() + 1);
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
+1
-7
@@ -20,16 +20,10 @@ import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest;
|
||||
public abstract class KotlinCodeInsightTestCase extends CodeInsightTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory());
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runTestRunnable(@NotNull ThrowableRunnable<Throwable> testRunnable) throws Throwable {
|
||||
KotlinTestUtils.runTestWithThrowable(this, () -> super.runTestRunnable(testRunnable));
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.test
|
||||
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestMetadata
|
||||
import java.io.File
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
|
||||
abstract class KotlinLightPlatformCodeInsightFixtureTestCase : LightPlatformCodeInsightFixtureTestCase() {
|
||||
protected open fun isFirPlugin(): Boolean = false
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
enableKotlinOfficialCodeStyle(project)
|
||||
runPostStartupActivitiesOnce(project)
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
if (!isFirPlugin()) {
|
||||
invalidateLibraryCache(project)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tearDown() = runAll(
|
||||
ThrowableRunnable { disableKotlinOfficialCodeStyle(project) },
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
)
|
||||
|
||||
protected fun testDataFile(fileName: String): File = File(testDataPath, fileName)
|
||||
|
||||
protected fun testDataFile(): File = testDataFile(fileName())
|
||||
|
||||
protected fun testPath(fileName: String = fileName()): String = testDataFile(fileName).toString()
|
||||
|
||||
protected fun testPath(): String = testPath(fileName())
|
||||
|
||||
protected open fun fileName(): String = KotlinTestUtils.getTestDataFileName(this::class.java, this.name) ?: (getTestName(false) + ".kt")
|
||||
|
||||
override fun getTestDataPath(): String = this::class.findAnnotation<TestMetadata>()?.value ?: super.getTestDataPath()
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.test
|
||||
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.refactoring.MultiFileTestCase
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
|
||||
abstract class KotlinMultiFileTestCase : MultiFileTestCase() {
|
||||
protected var isMultiModule = false
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
|
||||
runWriteAction {
|
||||
PluginTestCaseBase.addJdk(testRootDisposable, PluginTestCaseBase::mockJdk6)
|
||||
ProjectRootManager.getInstance(project).projectSdk = PluginTestCaseBase.mockJdk6()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getTestDirName(lowercaseFirstLetter: Boolean): String {
|
||||
val testName = getTestName(lowercaseFirstLetter)
|
||||
val endIndex = testName.lastIndexOf('_')
|
||||
if (endIndex < 0) return testName
|
||||
return testName.substring(0, endIndex).replace('_', '/')
|
||||
}
|
||||
|
||||
protected fun doTestCommittingDocuments(action: (VirtualFile, VirtualFile?) -> Unit) {
|
||||
super.doTest(
|
||||
{ rootDir, rootAfter ->
|
||||
action(rootDir, rootAfter)
|
||||
|
||||
PsiDocumentManager.getInstance(project!!).commitAllDocuments()
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
}, getTestDirName(true)
|
||||
)
|
||||
}
|
||||
|
||||
override fun prepareProject(rootDir: VirtualFile) {
|
||||
if (isMultiModule) {
|
||||
val model = ModuleManager.getInstance(project).modifiableModel
|
||||
|
||||
VfsUtilCore.visitChildrenRecursively(
|
||||
rootDir,
|
||||
object : VirtualFileVisitor<Any>() {
|
||||
override fun visitFile(file: VirtualFile): Boolean {
|
||||
if (!file.isDirectory && file.name.endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) {
|
||||
model.loadModule(file.path)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
runWriteAction { model.commit() }
|
||||
} else {
|
||||
PsiTestUtil.addSourceContentToRoots(myModule, rootDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||
package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading
|
||||
|
||||
import com.sun.jdi.ArrayReference
|
||||
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.scratch
|
||||
|
||||
import com.intellij.ide.scratch.ScratchFileService
|
||||
import com.intellij.ide.scratch.ScratchRootType
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.CompilerModuleExtension
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.testFramework.FileEditorManagerTestCase
|
||||
import com.intellij.testFramework.MapDataContext
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.TestActionEvent
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
|
||||
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction
|
||||
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
|
||||
import org.jetbrains.kotlin.idea.scratch.actions.ScratchCompilationSupport
|
||||
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer
|
||||
import org.jetbrains.kotlin.idea.scratch.ui.KtScratchFileEditorWithPreview
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition.Companion.STD_SCRIPT_SUFFIX
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
|
||||
|
||||
fun doRightPreviewPanelOutputTest(fileName: String) {
|
||||
doRightPreviewPanelOutputTest(fileName = fileName, isRepl = false)
|
||||
}
|
||||
|
||||
fun doWorksheetReplTest(fileName: String) {
|
||||
doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = true)
|
||||
}
|
||||
|
||||
fun doScratchReplTest(fileName: String) {
|
||||
doInlayOutputTest(fileName = fileName, isRepl = true, isWorksheet = false)
|
||||
}
|
||||
|
||||
fun doWorksheetCompilingTest(fileName: String) {
|
||||
doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = true)
|
||||
}
|
||||
|
||||
fun doScratchCompilingTest(fileName: String) {
|
||||
doInlayOutputTest(fileName = fileName, isRepl = false, isWorksheet = false)
|
||||
}
|
||||
|
||||
fun doWorksheetMultiFileTest(dirName: String) {
|
||||
doMultiFileTest(dirName, isWorksheet = true)
|
||||
}
|
||||
|
||||
fun doScratchMultiFileTest(dirName: String) {
|
||||
doMultiFileTest(dirName, isWorksheet = false)
|
||||
}
|
||||
|
||||
private fun doMultiFileTest(dirName: String, isWorksheet: Boolean) {
|
||||
val mainFileExtension = if (isWorksheet) KOTLIN_WORKSHEET_EXTENSION else STD_SCRIPT_SUFFIX
|
||||
|
||||
val javaFiles = arrayListOf<File>()
|
||||
val kotlinFiles = arrayListOf<File>()
|
||||
val baseDir = File(testDataPath, dirName)
|
||||
baseDir.walk().forEach {
|
||||
if (it.isFile) {
|
||||
if (it.extension == "java") javaFiles.add(it)
|
||||
if (it.extension == "kt") kotlinFiles.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
val testDataPathFile = File(myFixture.testDataPath)
|
||||
javaFiles.forEach {
|
||||
myFixture.copyFileToProject(
|
||||
FileUtil.getRelativePath(testDataPathFile, it)!!,
|
||||
FileUtil.getRelativePath(baseDir, it)!!
|
||||
)
|
||||
}
|
||||
kotlinFiles.forEach {
|
||||
myFixture.copyFileToProject(
|
||||
FileUtil.getRelativePath(testDataPathFile, it)!!,
|
||||
FileUtil.getRelativePath(baseDir, it)!!
|
||||
)
|
||||
}
|
||||
|
||||
val outputDir = FileUtil.createTempDirectory(dirName, "")
|
||||
|
||||
if (javaFiles.isNotEmpty()) {
|
||||
val options = listOf("-d", outputDir.path)
|
||||
KotlinTestUtils.compileJavaFiles(javaFiles, options)
|
||||
}
|
||||
|
||||
MockLibraryUtil.compileKotlin(baseDir.path, outputDir)
|
||||
|
||||
PsiTestUtil.setCompilerOutputPath(myFixture.module, outputDir.path, false)
|
||||
|
||||
val mainFileName = "$dirName/${getTestName(true)}.$mainFileExtension"
|
||||
doInlayOutputTest(mainFileName, isRepl = false, isWorksheet = isWorksheet)
|
||||
|
||||
launchAction(ClearScratchAction())
|
||||
|
||||
doInlayOutputTest(mainFileName, isRepl = true, isWorksheet = isWorksheet)
|
||||
|
||||
ModuleRootModificationUtil.updateModel(myFixture.module) { model ->
|
||||
model.getModuleExtension(CompilerModuleExtension::class.java).inheritCompilerOutputPath(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doInlayOutputTest(fileName: String, isRepl: Boolean, isWorksheet: Boolean) {
|
||||
configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = isWorksheet)
|
||||
|
||||
val actualOutput = getFileTextWithInlays()
|
||||
|
||||
val expectedFile = getExpectedFile(fileName, isRepl, suffix = "after")
|
||||
KotlinTestUtils.assertEqualsToFile(expectedFile, actualOutput)
|
||||
}
|
||||
|
||||
private fun doRightPreviewPanelOutputTest(fileName: String, isRepl: Boolean) {
|
||||
configureAndLaunchScratch(fileName = fileName, isRepl = isRepl, isWorksheet = false)
|
||||
|
||||
val previewTextWithFoldings = getPreviewTextWithFoldings()
|
||||
|
||||
val expectedFile = getExpectedFile(fileName, isRepl, suffix = "preview")
|
||||
KotlinTestUtils.assertEqualsToFile(expectedFile, previewTextWithFoldings)
|
||||
}
|
||||
|
||||
private fun configureAndLaunchScratch(fileName: String, isRepl: Boolean, isWorksheet: Boolean) {
|
||||
val sourceFile = File(testDataPath, fileName)
|
||||
val fileText = sourceFile.readText().inlinePropertiesValues(isRepl)
|
||||
|
||||
if (isWorksheet) {
|
||||
configureWorksheetByText(sourceFile.name, fileText)
|
||||
} else {
|
||||
configureScratchByText(sourceFile.name, fileText)
|
||||
}
|
||||
|
||||
if (!KotlinHighlightingUtil.shouldHighlight(myFixture.file)) error("Highlighting for scratch file is switched off")
|
||||
|
||||
launchScratch()
|
||||
waitUntilScratchFinishes(isRepl)
|
||||
}
|
||||
|
||||
private fun getExpectedFile(fileName: String, isRepl: Boolean, suffix: String): File {
|
||||
val expectedFileName = if (isRepl) {
|
||||
fileName.replace(".kts", ".repl.$suffix")
|
||||
} else {
|
||||
fileName.replace(".kts", ".comp.$suffix")
|
||||
}
|
||||
|
||||
return File(testDataPath, expectedFileName)
|
||||
}
|
||||
|
||||
protected fun String.inlinePropertiesValues(
|
||||
isRepl: Boolean = false,
|
||||
isInteractiveMode: Boolean = false
|
||||
): String {
|
||||
return replace("~REPL_MODE~", isRepl.toString()).replace("~INTERACTIVE_MODE~", isInteractiveMode.toString())
|
||||
}
|
||||
|
||||
protected fun getFileTextWithInlays(): String {
|
||||
val doc = myFixture.getDocument(myFixture.file) ?: error("Document for ${myFixture.file.name} is null")
|
||||
val actualOutput = StringBuilder(myFixture.file.text)
|
||||
for (line in doc.lineCount - 1 downTo 0) {
|
||||
getInlays(doc.getLineStartOffset(line), doc.getLineEndOffset(line))
|
||||
.forEach { inlay ->
|
||||
val str = inlay.toString()
|
||||
val offset = doc.getLineEndOffset(line)
|
||||
actualOutput.insert(
|
||||
offset,
|
||||
"${str.takeWhile { it.isWhitespace() }}// ${str.trim()}"
|
||||
)
|
||||
}
|
||||
}
|
||||
return actualOutput.toString().trim()
|
||||
}
|
||||
|
||||
private fun getPreviewTextWithFoldings(): String {
|
||||
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
|
||||
?: error("Couldn't find scratch panel")
|
||||
|
||||
val previewEditor = scratchFileEditor.getPreviewEditor()
|
||||
return getFoldingData(previewEditor.editor, withCollapseStatus = false)
|
||||
}
|
||||
|
||||
protected fun getInlays(start: Int = 0, end: Int = myFixture.file.textLength): List<InlayScratchFileRenderer> {
|
||||
val inlineElementsInRange = myFixture.editor.inlayModel
|
||||
.getAfterLineEndElementsInRange(start, end)
|
||||
.filter { it.renderer is InlayScratchFileRenderer }
|
||||
return inlineElementsInRange.map { it.renderer as InlayScratchFileRenderer }
|
||||
}
|
||||
|
||||
protected fun configureScratchByText(name: String, text: String): ScratchFile {
|
||||
val scratchVirtualFile = ScratchRootType.getInstance().createScratchFile(
|
||||
project,
|
||||
name,
|
||||
KotlinLanguage.INSTANCE,
|
||||
text,
|
||||
ScratchFileService.Option.create_if_missing
|
||||
) ?: error("Couldn't create scratch file")
|
||||
|
||||
myFixture.openFileInEditor(scratchVirtualFile)
|
||||
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
|
||||
|
||||
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
|
||||
?: error("Couldn't find scratch file")
|
||||
|
||||
configureOptions(scratchFileEditor, text, myFixture.module)
|
||||
|
||||
return scratchFileEditor.scratchFile
|
||||
}
|
||||
|
||||
protected fun configureWorksheetByText(name: String, text: String): ScratchFile {
|
||||
val worksheetFile = myFixture.configureByText(name, text).virtualFile
|
||||
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file)
|
||||
|
||||
val scratchFileEditor = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)
|
||||
?: error("Couldn't find scratch panel")
|
||||
|
||||
// We want to check that correct module is selected automatically,
|
||||
// that's why we set `module` to null so it wouldn't be changed
|
||||
configureOptions(scratchFileEditor, text, null)
|
||||
|
||||
return scratchFileEditor.scratchFile
|
||||
}
|
||||
|
||||
|
||||
protected fun launchScratch() {
|
||||
val action = RunScratchAction()
|
||||
launchAction(action)
|
||||
}
|
||||
|
||||
protected fun launchAction(action: AnAction) {
|
||||
val e = getActionEvent(myFixture.file.virtualFile, action)
|
||||
action.beforeActionPerformedUpdate(e)
|
||||
Assert.assertTrue(e.presentation.isEnabled && e.presentation.isVisible)
|
||||
action.actionPerformed(e)
|
||||
}
|
||||
|
||||
protected fun waitUntilScratchFinishes(shouldStopRepl: Boolean = true) {
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
|
||||
val start = System.currentTimeMillis()
|
||||
// wait until output is displayed in editor or for 1 minute
|
||||
while (ScratchCompilationSupport.isAnyInProgress()) {
|
||||
if ((System.currentTimeMillis() - start) > TIME_OUT) {
|
||||
LOG.warn("Waiting timeout $TIME_OUT ms is exceed")
|
||||
break
|
||||
}
|
||||
Thread.sleep(100)
|
||||
}
|
||||
|
||||
if (shouldStopRepl) stopReplProcess()
|
||||
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
}
|
||||
|
||||
protected fun stopReplProcess() {
|
||||
if (myFixture.file != null) {
|
||||
val scratchFile = getScratchEditorForSelectedFile(myManager, myFixture.file.virtualFile)?.scratchFile
|
||||
?: error("Couldn't find scratch panel")
|
||||
scratchFile.replScratchExecutor?.stopAndWait()
|
||||
}
|
||||
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
}
|
||||
|
||||
private fun getActionEvent(virtualFile: VirtualFile, action: AnAction): TestActionEvent {
|
||||
val context = MapDataContext()
|
||||
context.put(CommonDataKeys.VIRTUAL_FILE_ARRAY, arrayOf(virtualFile))
|
||||
context.put(CommonDataKeys.PROJECT, project)
|
||||
context.put(CommonDataKeys.EDITOR, myFixture.editor)
|
||||
return TestActionEvent(context, action)
|
||||
}
|
||||
|
||||
protected fun testScratchText(): String {
|
||||
return File(testDataPath, "idea/scripting-support/testData/scratch/custom/test_scratch.kts").readText()
|
||||
}
|
||||
|
||||
override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory()
|
||||
|
||||
|
||||
override fun getProjectDescriptor(): com.intellij.testFramework.LightProjectDescriptor {
|
||||
val testName = getTestName(false)
|
||||
|
||||
return when {
|
||||
testName.endsWith("WithKotlinTest") -> INSTANCE_WITH_KOTLIN_TEST
|
||||
testName.endsWith("NoRuntime") -> INSTANCE_WITHOUT_RUNTIME
|
||||
testName.endsWith("ScriptRuntime") -> INSTANCE_WITH_SCRIPT_RUNTIME
|
||||
else -> KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory())
|
||||
|
||||
PluginTestCaseBase.addJdk(myFixture.projectDisposable) { PluginTestCaseBase.fullJdk() }
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
super.tearDown()
|
||||
|
||||
ScratchFileService.getInstance().scratchesMapping.mappings.forEach { file, _ ->
|
||||
runWriteAction { file.delete(this) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TIME_OUT = 60000 // 1 min
|
||||
|
||||
private val INSTANCE_WITH_KOTLIN_TEST = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
|
||||
arrayListOf(
|
||||
ForTestCompileRuntime.runtimeJarForTests(),
|
||||
PathUtil.kotlinPathsForDistDirectory.kotlinTestPath
|
||||
)
|
||||
) {
|
||||
override fun getSdk() = PluginTestCaseBase.fullJdk()
|
||||
}
|
||||
|
||||
private val INSTANCE_WITHOUT_RUNTIME = object : KotlinLightProjectDescriptor() {
|
||||
override fun getSdk() = PluginTestCaseBase.fullJdk()
|
||||
}
|
||||
|
||||
private val INSTANCE_WITH_SCRIPT_RUNTIME = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
|
||||
arrayListOf(
|
||||
ForTestCompileRuntime.runtimeJarForTests(),
|
||||
ForTestCompileRuntime.scriptRuntimeJarForTests()
|
||||
)
|
||||
) {
|
||||
override fun getSdk() = PluginTestCaseBase.fullJdk()
|
||||
}
|
||||
|
||||
fun configureOptions(
|
||||
scratchFileEditor: KtScratchFileEditorWithPreview,
|
||||
fileText: String,
|
||||
module: Module?
|
||||
) {
|
||||
val scratchFile = scratchFileEditor.scratchFile
|
||||
|
||||
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// INTERACTIVE_MODE: ") != true) {
|
||||
scratchFile.saveOptions { copy(isInteractiveMode = false) }
|
||||
}
|
||||
|
||||
if (InTextDirectivesUtils.getPrefixedBoolean(fileText, "// REPL_MODE: ") == true) {
|
||||
scratchFile.saveOptions { copy(isRepl = true) }
|
||||
}
|
||||
|
||||
if (module != null && !InTextDirectivesUtils.isDirectiveDefined(fileText, "// NO_MODULE")) {
|
||||
scratchFile.setModule(module)
|
||||
}
|
||||
|
||||
val isPreviewEnabled = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// PREVIEW_ENABLED: ") == true
|
||||
scratchFileEditor.setPreviewEnabled(isPreviewEnabled)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.intellij.codeInsight.javadoc.JavaDocExternalFilter
|
||||
import com.intellij.psi.PsiDocCommentBase
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.function.Consumer
|
||||
|
||||
// FIX ME WHEN BUNCH 201 REMOVED
|
||||
class KotlinDocumentationProvider : KotlinDocumentationProviderCompatBase() {
|
||||
|
||||
override fun collectDocComments(file: PsiFile, sink: Consumer<in PsiDocCommentBase>) {
|
||||
if (file !is KtFile) return
|
||||
|
||||
PsiTreeUtil.processElements(file) {
|
||||
val comment = (it as? KtDeclaration)?.docComment
|
||||
if (comment != null) sink.accept(comment)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateRenderedDoc(element: PsiElement): String? {
|
||||
val docComment = (element as? KtDeclaration)?.docComment ?: return null
|
||||
|
||||
val result = StringBuilder().also {
|
||||
it.renderKDoc(docComment.getDefaultSection(), docComment.getAllSections())
|
||||
}
|
||||
|
||||
return JavaDocExternalFilter.filterInternalDocInfo(result.toString())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.framework
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.projectRoots.*
|
||||
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl
|
||||
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
|
||||
import com.intellij.util.Consumer
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import javax.swing.JComponent
|
||||
|
||||
class KotlinSdkType : SdkType("KotlinSDK") {
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = KotlinSdkType()
|
||||
|
||||
val defaultHomePath: String
|
||||
get() = PathUtil.kotlinPathsForIdeaPlugin.homePath.absolutePath
|
||||
|
||||
@JvmOverloads
|
||||
fun setUpIfNeeded(disposable: Disposable? = null, checkIfNeeded: () -> Boolean = { true }) {
|
||||
val projectSdks: Array<Sdk> = ProjectJdkTable.getInstance().allJdks
|
||||
if (projectSdks.any { it.sdkType is KotlinSdkType }) return
|
||||
if (!checkIfNeeded()) return // do not create Kotlin SDK
|
||||
|
||||
val newSdkName = SdkConfigurationUtil.createUniqueSdkName(INSTANCE, defaultHomePath, projectSdks.toList())
|
||||
val newJdk = ProjectJdkImpl(newSdkName, INSTANCE)
|
||||
newJdk.homePath = defaultHomePath
|
||||
INSTANCE.setupSdkPaths(newJdk)
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait {
|
||||
runWriteAction {
|
||||
if (ProjectJdkTable.getInstance().allJdks.any { it.sdkType is KotlinSdkType }) return@runWriteAction
|
||||
if (disposable != null) {
|
||||
ProjectJdkTable.getInstance().addJdk(newJdk, disposable)
|
||||
} else {
|
||||
ProjectJdkTable.getInstance().addJdk(newJdk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPresentableName() = KotlinBundle.message("framework.name.kotlin.sdk")
|
||||
|
||||
override fun getIcon() = KotlinIcons.SMALL_LOGO
|
||||
|
||||
override fun isValidSdkHome(path: String?) = true
|
||||
|
||||
override fun suggestSdkName(currentSdkName: String?, sdkHome: String?) = "Kotlin SDK"
|
||||
|
||||
override fun suggestHomePath() = null
|
||||
|
||||
override fun sdkHasValidPath(sdk: Sdk) = true
|
||||
|
||||
override fun getVersionString(sdk: Sdk) = bundledRuntimeVersion()
|
||||
|
||||
override fun supportsCustomCreateUI() = true
|
||||
|
||||
override fun showCustomCreateUI(sdkModel: SdkModel, parentComponent: JComponent, selectedSdk: Sdk?, sdkCreatedCallback: Consumer<in Sdk>) {
|
||||
sdkCreatedCallback.consume(createSdkWithUniqueName(sdkModel.sdks.toList()))
|
||||
}
|
||||
|
||||
fun createSdkWithUniqueName(existingSdks: Collection<Sdk>): ProjectJdkImpl {
|
||||
val sdkName = suggestSdkName(SdkConfigurationUtil.createUniqueSdkName(this, "", existingSdks), "")
|
||||
return ProjectJdkImpl(sdkName, this).apply {
|
||||
homePath = defaultHomePath
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAdditionalDataConfigurable(sdkModel: SdkModel, sdkModificator: SdkModificator) = null
|
||||
|
||||
override fun saveAdditionalData(additionalData: SdkAdditionalData, additional: Element) {
|
||||
|
||||
}
|
||||
|
||||
override fun allowCreationByUser(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.reporter
|
||||
|
||||
import com.intellij.diagnostic.ITNReporter
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
|
||||
import com.intellij.openapi.diagnostic.SubmittedReportInfo
|
||||
import com.intellij.util.Consumer
|
||||
import java.awt.Component
|
||||
|
||||
abstract class ITNReporterCompat : ITNReporter() {
|
||||
final override fun submit(
|
||||
events: Array<IdeaLoggingEvent>,
|
||||
additionalInfo: String?,
|
||||
parentComponent: Component,
|
||||
consumer: Consumer<in SubmittedReportInfo>
|
||||
): Boolean {
|
||||
return submitCompat(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
open fun submitCompat(
|
||||
events: Array<IdeaLoggingEvent>,
|
||||
additionalInfo: String?,
|
||||
parentComponent: Component?,
|
||||
consumer: Consumer<in SubmittedReportInfo>
|
||||
): Boolean {
|
||||
@Suppress("IncompatibleAPI")
|
||||
return super.submit(events, additionalInfo, parentComponent ?: error("Should never happen in Intellij Idea"), consumer)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.reporter
|
||||
|
||||
import com.intellij.diagnostic.ReportMessages
|
||||
import com.intellij.ide.DataManager
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.SubmittedReportInfo
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.util.Consumer
|
||||
import com.intellij.util.ThreeState
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUpdater
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import org.jetbrains.kotlin.idea.PluginUpdateStatus
|
||||
import org.jetbrains.kotlin.idea.util.isEap
|
||||
import java.awt.Component
|
||||
import java.io.IOException
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.DateTimeParseException
|
||||
import java.time.temporal.ChronoUnit
|
||||
import javax.swing.Icon
|
||||
|
||||
/**
|
||||
* We need to wrap ITNReporter for force showing or errors from kotlin plugin even from released version of IDEA.
|
||||
*/
|
||||
class KotlinReportSubmitter : ITNReporterCompat() {
|
||||
companion object {
|
||||
private const val KOTLIN_FATAL_ERROR_NOTIFICATION_PROPERTY = "kotlin.fatal.error.notification"
|
||||
private const val IDEA_FATAL_ERROR_NOTIFICATION_PROPERTY = "idea.fatal.error.notification"
|
||||
private const val DISABLED_VALUE = "disabled"
|
||||
private const val ENABLED_VALUE = "enabled"
|
||||
|
||||
private const val KOTLIN_PLUGIN_RELEASE_DATE = "kotlin.plugin.releaseDate"
|
||||
|
||||
private val LOG = Logger.getInstance(KotlinReportSubmitter::class.java)
|
||||
|
||||
@Volatile
|
||||
private var isFatalErrorReportingDisabledInRelease = ThreeState.UNSURE
|
||||
|
||||
private val isIdeaAndKotlinRelease by lazy {
|
||||
// Disabled in released version of IDEA and Android Studio
|
||||
// Enabled in EAPs, Canary and Beta
|
||||
val isReleaseLikeIdea = DISABLED_VALUE == System.getProperty(IDEA_FATAL_ERROR_NOTIFICATION_PROPERTY, ENABLED_VALUE)
|
||||
|
||||
val isKotlinRelease =
|
||||
!(KotlinPluginUtil.isSnapshotVersion() || KotlinPluginUtil.isDevVersion() || isEap(KotlinPluginUtil.getPluginVersion()))
|
||||
|
||||
isReleaseLikeIdea && isKotlinRelease
|
||||
}
|
||||
|
||||
private const val NUMBER_OF_REPORTING_DAYS_FROM_RELEASE = 7
|
||||
|
||||
fun setupReportingFromRelease() {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isIdeaAndKotlinRelease) {
|
||||
return
|
||||
}
|
||||
|
||||
val currentPluginReleaseDate = readStoredPluginReleaseDate()
|
||||
if (currentPluginReleaseDate != null) {
|
||||
isFatalErrorReportingDisabledInRelease =
|
||||
if (isFatalErrorReportingDisabled(currentPluginReleaseDate)) ThreeState.YES else ThreeState.NO
|
||||
return
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
val releaseDate =
|
||||
try {
|
||||
KotlinPluginUpdater.fetchPluginReleaseDate(
|
||||
KotlinPluginUtil.KOTLIN_PLUGIN_ID,
|
||||
KotlinPluginUtil.getPluginVersion(),
|
||||
null
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
LOG.warn(e)
|
||||
null
|
||||
} catch (e: KotlinPluginUpdater.Companion.ResponseParseException) {
|
||||
// Exception won't be shown, but will be logged
|
||||
LOG.error(e)
|
||||
return@executeOnPooledThread
|
||||
}
|
||||
|
||||
if (releaseDate != null) {
|
||||
writePluginReleaseValue(releaseDate)
|
||||
} else {
|
||||
// Will try to fetch the same release date on IDE restart
|
||||
}
|
||||
|
||||
isFatalErrorReportingDisabledInRelease = isFatalErrorReportingWithDefault(releaseDate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFatalErrorReportingWithDefault(releaseDate: LocalDate?): ThreeState {
|
||||
return if (releaseDate != null) {
|
||||
if (isFatalErrorReportingDisabled(releaseDate)) ThreeState.YES else ThreeState.NO
|
||||
} else {
|
||||
// Disable reporting by default until we obtain a valid release date.
|
||||
// We might fail reporting exceptions that happened before initialization but after successful release date fetching
|
||||
// such exceptions maybe be reported after restart.
|
||||
ThreeState.YES
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFatalErrorReportingDisabledWithUpdate(): Boolean {
|
||||
val currentPluginReleaseDate = readStoredPluginReleaseDate()
|
||||
isFatalErrorReportingDisabledInRelease = isFatalErrorReportingWithDefault(currentPluginReleaseDate)
|
||||
|
||||
return isFatalErrorReportingDisabledInRelease == ThreeState.YES
|
||||
}
|
||||
|
||||
private fun isFatalErrorReportingDisabled(releaseDate: LocalDate): Boolean {
|
||||
return ChronoUnit.DAYS.between(releaseDate, LocalDate.now()) > NUMBER_OF_REPORTING_DAYS_FROM_RELEASE
|
||||
}
|
||||
|
||||
private val RELEASE_DATE_FORMATTER: DateTimeFormatter by lazy {
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
||||
}
|
||||
|
||||
private fun readStoredPluginReleaseDate(): LocalDate? {
|
||||
val pluginVersionToReleaseDate = PropertiesComponent.getInstance().getValue(KOTLIN_PLUGIN_RELEASE_DATE) ?: return null
|
||||
|
||||
val parsedDate = fun(): LocalDate? {
|
||||
val parts = pluginVersionToReleaseDate.split(":")
|
||||
if (parts.size != 2) {
|
||||
return null
|
||||
}
|
||||
|
||||
val pluginVersion = parts[0]
|
||||
if (pluginVersion != KotlinPluginUtil.getPluginVersion()) {
|
||||
// Stored for some other plugin version
|
||||
return null
|
||||
}
|
||||
|
||||
return try {
|
||||
val dateString = parts[1]
|
||||
LocalDate.parse(dateString, RELEASE_DATE_FORMATTER)
|
||||
} catch (e: DateTimeParseException) {
|
||||
null
|
||||
}
|
||||
}.invoke()
|
||||
|
||||
if (parsedDate == null) {
|
||||
PropertiesComponent.getInstance().setValue(KOTLIN_PLUGIN_RELEASE_DATE, null)
|
||||
}
|
||||
|
||||
return parsedDate
|
||||
}
|
||||
|
||||
private fun writePluginReleaseValue(date: LocalDate) {
|
||||
val currentKotlinVersion = KotlinPluginUtil.getPluginVersion()
|
||||
val dateStr = RELEASE_DATE_FORMATTER.format(date)
|
||||
PropertiesComponent.getInstance().setValue(KOTLIN_PLUGIN_RELEASE_DATE, "$currentKotlinVersion:$dateStr")
|
||||
}
|
||||
}
|
||||
|
||||
private var hasUpdate = false
|
||||
private var hasLatestVersion = false
|
||||
|
||||
override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean {
|
||||
if (ApplicationManager.getApplication().isInternal) {
|
||||
// Reporting is always enabled for internal mode in the platform
|
||||
return true
|
||||
}
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (hasUpdate) {
|
||||
return false
|
||||
}
|
||||
|
||||
val kotlinNotificationEnabled = DISABLED_VALUE != System.getProperty(KOTLIN_FATAL_ERROR_NOTIFICATION_PROPERTY, ENABLED_VALUE)
|
||||
if (!kotlinNotificationEnabled) {
|
||||
// Kotlin notifications are explicitly disabled
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isIdeaAndKotlinRelease) {
|
||||
return true
|
||||
}
|
||||
|
||||
return when (isFatalErrorReportingDisabledInRelease) {
|
||||
ThreeState.YES ->
|
||||
false
|
||||
|
||||
ThreeState.NO -> {
|
||||
// Reiterate the check for the case when there was no restart for long and reporting decision might expire
|
||||
!isFatalErrorReportingDisabledWithUpdate()
|
||||
}
|
||||
|
||||
ThreeState.UNSURE -> {
|
||||
// There might be an exception while initialization isn't complete.
|
||||
// Decide urgently based on previously stored release version if already fetched.
|
||||
!isFatalErrorReportingDisabledWithUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun submitCompat(
|
||||
events: Array<IdeaLoggingEvent>,
|
||||
additionalInfo: String?,
|
||||
parentComponent: Component?,
|
||||
consumer: Consumer<in SubmittedReportInfo>
|
||||
): Boolean {
|
||||
if (hasUpdate) {
|
||||
if (ApplicationManager.getApplication().isInternal) {
|
||||
return super.submitCompat(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
// TODO: What happens here? User clicks report but no report is send?
|
||||
return true
|
||||
}
|
||||
|
||||
if (hasLatestVersion) {
|
||||
return super.submitCompat(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
val project: Project? = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(parentComponent))
|
||||
if (KotlinPluginUtil.isPatched()) {
|
||||
ReportMessages.GROUP
|
||||
.createNotification(
|
||||
ReportMessages.ERROR_REPORT,
|
||||
KotlinBundle.message("reporter.text.can.t.report.exception.from.patched.plugin"),
|
||||
NotificationType.INFORMATION,
|
||||
null
|
||||
)
|
||||
.setImportant(false)
|
||||
.notify(project)
|
||||
return true
|
||||
}
|
||||
|
||||
KotlinPluginUpdater.getInstance().runUpdateCheck { status ->
|
||||
if (status is PluginUpdateStatus.Update) {
|
||||
hasUpdate = true
|
||||
|
||||
if (ApplicationManager.getApplication().isInternal) {
|
||||
super.submitCompat(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
val rc = showDialog(
|
||||
parentComponent,
|
||||
KotlinBundle.message(
|
||||
"reporter.message.text.you.re.running.kotlin.plugin.version",
|
||||
KotlinPluginUtil.getPluginVersion(),
|
||||
status.pluginDescriptor.version
|
||||
),
|
||||
KotlinBundle.message("reporter.title.update.kotlin.plugin"),
|
||||
arrayOf(KotlinBundle.message("reporter.button.text.update"), KotlinBundle.message("reporter.button.text.ignore")),
|
||||
0, Messages.getInformationIcon()
|
||||
)
|
||||
|
||||
if (rc == 0) {
|
||||
KotlinPluginUpdater.getInstance().installPluginUpdate(status)
|
||||
}
|
||||
} else {
|
||||
hasLatestVersion = true
|
||||
super.submitCompat(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun showDialog(parent: Component?, message: String, title: String, options: Array<String>, defaultOptionIndex: Int, icon: Icon?): Int {
|
||||
return if (parent != null) {
|
||||
Messages.showDialog(parent, message, title, options, defaultOptionIndex, icon)
|
||||
} else {
|
||||
Messages.showDialog(message, title, options, defaultOptionIndex, icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
|
||||
abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory());
|
||||
super.setUp();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.caches.resolve
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.StdModuleTypes
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.ModuleTestCase
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.idea.caches.project.*
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleTestSourceInfo
|
||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.platform
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.*
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.util.addDependency
|
||||
import org.jetbrains.kotlin.test.util.jarRoot
|
||||
import org.jetbrains.kotlin.test.util.projectLibrary
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import org.junit.Assert
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
class IdeaModuleInfoTest : ModuleTestCase() {
|
||||
fun testSimpleModuleDependency() {
|
||||
val (a, b) = modules()
|
||||
b.addDependency(a)
|
||||
|
||||
b.production.assertDependenciesEqual(b.production, a.production)
|
||||
UsefulTestCase.assertDoesntContain(a.production.dependencies(), b.production)
|
||||
}
|
||||
|
||||
fun testCircularDependency() {
|
||||
val (a, b) = modules()
|
||||
|
||||
b.addDependency(a)
|
||||
a.addDependency(b)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production, b.production)
|
||||
b.production.assertDependenciesEqual(b.production, a.production)
|
||||
}
|
||||
|
||||
fun testExportedDependency() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
c.addDependency(b)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production)
|
||||
b.production.assertDependenciesEqual(b.production, a.production)
|
||||
c.production.assertDependenciesEqual(c.production, b.production, a.production)
|
||||
}
|
||||
|
||||
fun testRedundantExportedDependency() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
c.addDependency(a)
|
||||
c.addDependency(b)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production)
|
||||
b.production.assertDependenciesEqual(b.production, a.production)
|
||||
c.production.assertDependenciesEqual(c.production, a.production, b.production)
|
||||
}
|
||||
|
||||
fun testCircularExportedDependency() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
c.addDependency(b, exported = true)
|
||||
a.addDependency(c, exported = true)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production, c.production, b.production)
|
||||
b.production.assertDependenciesEqual(b.production, a.production, c.production)
|
||||
c.production.assertDependenciesEqual(c.production, b.production, a.production)
|
||||
}
|
||||
|
||||
fun testSimpleLibDependency() {
|
||||
val a = module("a")
|
||||
val lib = projectLibrary()
|
||||
a.addDependency(lib)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production, lib.classes)
|
||||
}
|
||||
|
||||
fun testCircularExportedDependencyWithLib() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
val lib = projectLibrary()
|
||||
|
||||
a.addDependency(lib)
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
c.addDependency(b, exported = true)
|
||||
a.addDependency(c, exported = true)
|
||||
|
||||
b.addDependency(lib)
|
||||
c.addDependency(lib)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production, lib.classes, c.production, b.production)
|
||||
b.production.assertDependenciesEqual(b.production, a.production, c.production, lib.classes)
|
||||
c.production.assertDependenciesEqual(c.production, b.production, a.production, lib.classes)
|
||||
}
|
||||
|
||||
fun testSeveralModulesExportLibs() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
val lib1 = projectLibrary("lib1")
|
||||
val lib2 = projectLibrary("lib2")
|
||||
|
||||
a.addDependency(lib1, exported = true)
|
||||
b.addDependency(lib2, exported = true)
|
||||
c.addDependency(a)
|
||||
c.addDependency(b)
|
||||
|
||||
c.production.assertDependenciesEqual(c.production, a.production, lib1.classes, b.production, lib2.classes)
|
||||
}
|
||||
|
||||
fun testSeveralModulesExportSameLib() {
|
||||
val (a, b, c) = modules()
|
||||
|
||||
val lib = projectLibrary()
|
||||
|
||||
a.addDependency(lib, exported = true)
|
||||
b.addDependency(lib, exported = true)
|
||||
c.addDependency(a)
|
||||
c.addDependency(b)
|
||||
|
||||
c.production.assertDependenciesEqual(c.production, a.production, lib.classes, b.production)
|
||||
}
|
||||
|
||||
fun testRuntimeDependency() {
|
||||
val (a, b) = modules()
|
||||
|
||||
b.addDependency(a, dependencyScope = DependencyScope.RUNTIME)
|
||||
b.addDependency(projectLibrary(), dependencyScope = DependencyScope.RUNTIME)
|
||||
|
||||
b.production.assertDependenciesEqual(b.production)
|
||||
}
|
||||
|
||||
fun testProvidedDependency() {
|
||||
val (a, b) = modules()
|
||||
val lib = projectLibrary()
|
||||
|
||||
b.addDependency(a, dependencyScope = DependencyScope.PROVIDED)
|
||||
b.addDependency(lib, dependencyScope = DependencyScope.PROVIDED)
|
||||
|
||||
b.production.assertDependenciesEqual(b.production, a.production, lib.classes)
|
||||
}
|
||||
|
||||
fun testSimpleTestDependency() {
|
||||
val (a, b) = modules()
|
||||
b.addDependency(a, dependencyScope = DependencyScope.TEST)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production)
|
||||
a.test.assertDependenciesEqual(a.test, a.production)
|
||||
b.production.assertDependenciesEqual(b.production)
|
||||
b.test.assertDependenciesEqual(b.test, b.production, a.test, a.production)
|
||||
}
|
||||
|
||||
fun testLibTestDependency() {
|
||||
val a = module("a")
|
||||
val lib = projectLibrary()
|
||||
a.addDependency(lib, dependencyScope = DependencyScope.TEST)
|
||||
|
||||
a.production.assertDependenciesEqual(a.production)
|
||||
a.test.assertDependenciesEqual(a.test, a.production, lib.classes)
|
||||
}
|
||||
|
||||
fun testExportedTestDependency() {
|
||||
val (a, b, c) = modules()
|
||||
b.addDependency(a, exported = true)
|
||||
c.addDependency(b, dependencyScope = DependencyScope.TEST)
|
||||
|
||||
c.production.assertDependenciesEqual(c.production)
|
||||
c.test.assertDependenciesEqual(c.test, c.production, b.test, b.production, a.test, a.production)
|
||||
}
|
||||
|
||||
fun testDependents() {
|
||||
//NOTE: we do not differ between dependency kinds
|
||||
val (a, b, c) = modules(name1 = "a", name2 = "b", name3 = "c")
|
||||
val (d, e, f) = modules(name1 = "d", name2 = "e", name3 = "f")
|
||||
|
||||
b.addDependency(a, exported = true)
|
||||
|
||||
c.addDependency(a)
|
||||
|
||||
d.addDependency(c, exported = true)
|
||||
|
||||
e.addDependency(b)
|
||||
|
||||
f.addDependency(d)
|
||||
f.addDependency(e)
|
||||
|
||||
|
||||
a.test.assertDependentsEqual(a.test, b.test, c.test, e.test)
|
||||
a.production.assertDependentsEqual(a.production, a.test, b.production, b.test, c.production, c.test, e.production, e.test)
|
||||
|
||||
b.test.assertDependentsEqual(b.test, e.test)
|
||||
b.production.assertDependentsEqual(b.production, b.test, e.production, e.test)
|
||||
|
||||
|
||||
c.test.assertDependentsEqual(c.test, d.test, f.test)
|
||||
c.production.assertDependentsEqual(c.production, c.test, d.production, d.test, f.production, f.test)
|
||||
|
||||
d.test.assertDependentsEqual(d.test, f.test)
|
||||
d.production.assertDependentsEqual(d.production, d.test, f.production, f.test)
|
||||
|
||||
e.test.assertDependentsEqual(e.test, f.test)
|
||||
e.production.assertDependentsEqual(e.production, e.test, f.production, f.test)
|
||||
|
||||
f.test.assertDependentsEqual(f.test)
|
||||
f.production.assertDependentsEqual(f.production, f.test)
|
||||
}
|
||||
|
||||
fun testLibraryDependency1() {
|
||||
val lib1 = projectLibrary("lib1")
|
||||
val lib2 = projectLibrary("lib2")
|
||||
|
||||
val module = module("module")
|
||||
module.addDependency(lib1)
|
||||
module.addDependency(lib2)
|
||||
|
||||
lib1.classes.assertAdditionalLibraryDependencies(lib2.classes)
|
||||
lib2.classes.assertAdditionalLibraryDependencies(lib1.classes)
|
||||
}
|
||||
|
||||
fun testLibraryDependency2() {
|
||||
val lib1 = projectLibrary("lib1")
|
||||
val lib2 = projectLibrary("lib2")
|
||||
val lib3 = projectLibrary("lib3")
|
||||
|
||||
val (a, b, c) = modules()
|
||||
a.addDependency(lib1)
|
||||
b.addDependency(lib2)
|
||||
c.addDependency(lib3)
|
||||
|
||||
c.addDependency(a)
|
||||
c.addDependency(b)
|
||||
|
||||
lib1.classes.assertAdditionalLibraryDependencies()
|
||||
lib2.classes.assertAdditionalLibraryDependencies()
|
||||
lib3.classes.assertAdditionalLibraryDependencies(lib1.classes, lib2.classes)
|
||||
}
|
||||
|
||||
fun testLibraryDependency3() {
|
||||
val lib1 = projectLibrary("lib1")
|
||||
val lib2 = projectLibrary("lib2")
|
||||
val lib3 = projectLibrary("lib3")
|
||||
|
||||
val (a, b) = modules()
|
||||
a.addDependency(lib1)
|
||||
b.addDependency(lib2)
|
||||
|
||||
a.addDependency(lib3)
|
||||
b.addDependency(lib3)
|
||||
|
||||
lib1.classes.assertAdditionalLibraryDependencies(lib3.classes)
|
||||
lib2.classes.assertAdditionalLibraryDependencies(lib3.classes)
|
||||
lib3.classes.assertAdditionalLibraryDependencies(lib1.classes, lib2.classes)
|
||||
}
|
||||
|
||||
fun testRoots() {
|
||||
val a = module("a", hasProductionRoot = true, hasTestRoot = false)
|
||||
|
||||
val empty = module("empty", hasProductionRoot = false, hasTestRoot = false)
|
||||
a.addDependency(empty)
|
||||
|
||||
val b = module("b", hasProductionRoot = false, hasTestRoot = true)
|
||||
b.addDependency(a)
|
||||
|
||||
val c = module("c")
|
||||
c.addDependency(b)
|
||||
c.addDependency(a)
|
||||
|
||||
assertNotNull(a.productionSourceInfo())
|
||||
assertNull(a.testSourceInfo())
|
||||
|
||||
assertNull(empty.productionSourceInfo())
|
||||
assertNull(empty.testSourceInfo())
|
||||
|
||||
assertNull(b.productionSourceInfo())
|
||||
assertNotNull(b.testSourceInfo())
|
||||
|
||||
b.test.assertDependenciesEqual(b.test, a.production)
|
||||
c.test.assertDependenciesEqual(c.test, c.production, b.test, a.production)
|
||||
c.production.assertDependenciesEqual(c.production, a.production)
|
||||
}
|
||||
|
||||
fun testCommonLibraryDoesNotDependOnPlatform() {
|
||||
val stdlibCommon = stdlibCommon()
|
||||
val stdlibJvm = stdlibJvm()
|
||||
val stdlibJs = stdlibJs()
|
||||
|
||||
val a = module("a")
|
||||
a.addDependency(stdlibCommon)
|
||||
a.addDependency(stdlibJvm)
|
||||
|
||||
val b = module("b")
|
||||
b.addDependency(stdlibCommon)
|
||||
b.addDependency(stdlibJs)
|
||||
|
||||
stdlibCommon.classes.assertAdditionalLibraryDependencies()
|
||||
stdlibJvm.classes.assertAdditionalLibraryDependencies(stdlibCommon.classes)
|
||||
stdlibJs.classes.assertAdditionalLibraryDependencies(stdlibCommon.classes)
|
||||
}
|
||||
|
||||
fun testScriptDependenciesForModule() {
|
||||
val a = module("a")
|
||||
val b = module("b")
|
||||
|
||||
with(createFileInModule(a, "script.kts").moduleInfo) {
|
||||
dependencies().contains(a.production)
|
||||
dependencies().contains(a.test)
|
||||
!dependencies().contains(b.production)
|
||||
}
|
||||
}
|
||||
|
||||
fun testScriptDependenciesForProject() {
|
||||
val a = module("a")
|
||||
|
||||
val script = createFileInProject("script.kts").moduleInfo
|
||||
|
||||
!script.dependencies().contains(a.production)
|
||||
!script.dependencies().contains(a.test)
|
||||
|
||||
script.dependencies().firstIsInstance<ScriptDependenciesInfo.ForFile>()
|
||||
}
|
||||
|
||||
fun testSdkForScript() {
|
||||
// The first known jdk will be used for scripting if there is no jdk in the project
|
||||
runWriteAction {
|
||||
addJdk(testRootDisposable, ::mockJdk6)
|
||||
addJdk(testRootDisposable, ::mockJdk9)
|
||||
|
||||
ProjectRootManager.getInstance(project).projectSdk = null
|
||||
}
|
||||
|
||||
val firstSDK = getProjectJdkTableSafe().allJdks.first()
|
||||
|
||||
with(createFileInProject("script.kts").moduleInfo) {
|
||||
dependencies().filterIsInstance<SdkInfo>().single { it.sdk == firstSDK }
|
||||
}
|
||||
}
|
||||
|
||||
fun testSdkForScriptProjectSdk() {
|
||||
runWriteAction {
|
||||
addJdk(testRootDisposable, ::mockJdk6)
|
||||
addJdk(testRootDisposable, ::mockJdk9)
|
||||
|
||||
ProjectRootManager.getInstance(project).projectSdk = mockJdk9()
|
||||
}
|
||||
|
||||
with(createFileInProject("script.kts").moduleInfo) {
|
||||
dependencies().filterIsInstance<SdkInfo>().single { it.sdk == mockJdk9() }
|
||||
}
|
||||
}
|
||||
|
||||
fun testSdkForScriptModuleSdk() {
|
||||
val a = module("a")
|
||||
|
||||
runWriteAction {
|
||||
addJdk(testRootDisposable, ::mockJdk6)
|
||||
addJdk(testRootDisposable, ::mockJdk9)
|
||||
|
||||
ProjectRootManager.getInstance(project).projectSdk = mockJdk6()
|
||||
with(ModuleRootManager.getInstance(a).modifiableModel) {
|
||||
sdk = mockJdk9()
|
||||
commit()
|
||||
}
|
||||
}
|
||||
|
||||
with(createFileInModule(a, "script.kts").moduleInfo) {
|
||||
dependencies().filterIsInstance<SdkInfo>().first { it.sdk == mockJdk9() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFileInModule(module: Module, fileName: String, inTests: Boolean = false): VirtualFile {
|
||||
val fileToCopyIO = createTempFile(fileName, "")
|
||||
|
||||
for (contentEntry in ModuleRootManager.getInstance(module).contentEntries) {
|
||||
for (sourceFolder in contentEntry.sourceFolders) {
|
||||
if (((!inTests && !sourceFolder.isTestSource) || (inTests && sourceFolder.isTestSource)) && sourceFolder.file != null) {
|
||||
return runWriteAction {
|
||||
getVirtualFile(fileToCopyIO).copy(this, sourceFolder.file!!, fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error("Couldn't find source folder in ${module.name}")
|
||||
}
|
||||
|
||||
private fun createFileInProject(fileName: String): VirtualFile {
|
||||
return runWriteAction {
|
||||
getVirtualFile(createTempFile(fileName, "")).copy(this, project.baseDir, fileName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Module.addDependency(
|
||||
other: Module,
|
||||
dependencyScope: DependencyScope = DependencyScope.COMPILE,
|
||||
exported: Boolean = false
|
||||
) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported)
|
||||
|
||||
private val VirtualFile.moduleInfo: IdeaModuleInfo
|
||||
get() {
|
||||
return PsiManager.getInstance(project).findFile(this)!!.getModuleInfo()
|
||||
}
|
||||
|
||||
private val Module.production: ModuleProductionSourceInfo
|
||||
get() = productionSourceInfo()!!
|
||||
|
||||
private val Module.test: ModuleTestSourceInfo
|
||||
get() = testSourceInfo()!!
|
||||
|
||||
private val LibraryEx.classes: LibraryInfo
|
||||
get() = object : LibraryInfo(project!!, this) {
|
||||
override val platform: TargetPlatform
|
||||
get() = kind.platform
|
||||
}
|
||||
|
||||
private fun module(name: String, hasProductionRoot: Boolean = true, hasTestRoot: Boolean = true): Module {
|
||||
return createModuleFromTestData(createTempDirectory().absolutePath, name, StdModuleTypes.JAVA, false).apply {
|
||||
if (hasProductionRoot)
|
||||
PsiTestUtil.addSourceContentToRoots(this, dir(), false)
|
||||
if (hasTestRoot)
|
||||
PsiTestUtil.addSourceContentToRoots(this, dir(), true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dir() = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDirectory())!!
|
||||
|
||||
private fun modules(name1: String = "a", name2: String = "b", name3: String = "c") = Triple(module(name1), module(name2), module(name3))
|
||||
|
||||
private fun IdeaModuleInfo.assertDependenciesEqual(vararg expected: IdeaModuleInfo) {
|
||||
Assert.assertEquals(expected.toList(), this.dependencies())
|
||||
}
|
||||
|
||||
private fun LibraryInfo.assertAdditionalLibraryDependencies(vararg expected: IdeaModuleInfo) {
|
||||
Assert.assertEquals(this, dependencies().first())
|
||||
val dependenciesWithoutSelf = this.dependencies().drop(1)
|
||||
UsefulTestCase.assertSameElements(dependenciesWithoutSelf, expected.toList())
|
||||
}
|
||||
|
||||
private fun ModuleSourceInfo.assertDependentsEqual(vararg expected: ModuleSourceInfo) {
|
||||
UsefulTestCase.assertSameElements(this.getDependentModules(), expected.toList())
|
||||
}
|
||||
|
||||
private fun stdlibCommon(): LibraryEx = projectLibrary(
|
||||
"kotlin-stdlib-common",
|
||||
ForTestCompileRuntime.stdlibCommonForTests().jarRoot,
|
||||
kind = CommonLibraryKind
|
||||
)
|
||||
|
||||
private fun stdlibJvm(): LibraryEx = projectLibrary("kotlin-stdlib", ForTestCompileRuntime.runtimeJarForTests().jarRoot)
|
||||
|
||||
private fun stdlibJs(): LibraryEx = projectLibrary(
|
||||
"kotlin-stdlib-js",
|
||||
ForTestCompileRuntime.runtimeJarForTests().jarRoot,
|
||||
kind = JSLibraryKind
|
||||
)
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -36,12 +36,11 @@ abstract class AbstractConfigureKotlinTest : PlatformTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory())
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun tearDown() {
|
||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
||||
PathMacros.getInstance().removeMacro(TEMP_DIR_MACRO_KEY)
|
||||
|
||||
super.tearDown()
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.repl
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleRunner
|
||||
import org.jetbrains.kotlin.idea.completion.test.KotlinFixtureCompletionBaseTestCase
|
||||
import org.jetbrains.kotlin.idea.completion.test.testCompletion
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractIdeReplCompletionTest : KotlinFixtureCompletionBaseTestCase() {
|
||||
private var consoleRunner: KotlinConsoleRunner? = null
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(consoleRunner!!.consoleFile)
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
consoleRunner?.dispose()
|
||||
consoleRunner = null
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
override fun getPlatform() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
override fun defaultCompletionType() = CompletionType.BASIC
|
||||
|
||||
override fun doTest(testPath: String) {
|
||||
val runner = consoleRunner!!
|
||||
val file = File(testPath)
|
||||
val lines = file.readLines()
|
||||
lines.prefixedWith(">> ").forEach { runner.successfulLine(it) } // not actually executing anything, only simulating
|
||||
val codeSample = lines.prefixedWith("-- ").joinToString("\n")
|
||||
|
||||
runWriteAction {
|
||||
val editor = runner.consoleView.editorDocument
|
||||
editor.setText(codeSample)
|
||||
FileDocumentManager.getInstance().saveDocument(runner.consoleView.editorDocument)
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
}
|
||||
|
||||
myFixture.configureFromExistingVirtualFile(runner.consoleFile.virtualFile)
|
||||
myFixture.editor.caretModel.moveToOffset(myFixture.editor.document.getLineEndOffset(0))
|
||||
|
||||
testCompletion(file.readText(), getPlatform(), { completionType, count -> myFixture.complete(completionType, count) })
|
||||
}
|
||||
|
||||
private fun List<String>.prefixedWith(prefix: String) = filter { it.startsWith(prefix) }.map { it.removePrefix(prefix) }
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = FullJdkProjectDescriptor
|
||||
}
|
||||
|
||||
private object FullJdkProjectDescriptor : KotlinWithJdkAndRuntimeLightProjectDescriptor() {
|
||||
override fun getSdk() = PluginTestCaseBase.fullJdk()
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.repl
|
||||
|
||||
import com.intellij.execution.console.LanguageConsoleImpl
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.testFramework.PlatformTestCase
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
|
||||
import org.jetbrains.kotlin.console.KotlinConsoleRunner
|
||||
import org.jetbrains.kotlin.idea.run.createLibraryWithLongPaths
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
|
||||
import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest
|
||||
import org.jetbrains.kotlin.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@RunWith(JUnit3WithIdeaConfigurationRunner::class)
|
||||
@WithMutedInDatabaseRunTest
|
||||
class IdeReplExecutionTest : PlatformTestCase() {
|
||||
private lateinit var consoleRunner: KotlinConsoleRunner
|
||||
private var commandsSent = 0
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
consoleRunner.dispose()
|
||||
(this::consoleRunner as KMutableProperty0<KotlinConsoleRunner?>).set(null)
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
override fun runTestRunnable(testRunnable: ThrowableRunnable<Throwable>) {
|
||||
runTest {
|
||||
super.runTestRunnable(testRunnable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendCommand(command: String) {
|
||||
runWriteAction { consoleRunner.consoleView.editorDocument.setText(command) }
|
||||
consoleRunner.executor.executeCommand()
|
||||
commandsSent++
|
||||
}
|
||||
|
||||
private fun checkOutput(expectedOutput: String) {
|
||||
val output = getReplOutput(textOnTimeOut = {
|
||||
"Only ${consoleRunner.commandHistory.processedEntriesCount} commands were processed"
|
||||
}) { consoleRunner.commandHistory.processedEntriesCount >= commandsSent }
|
||||
assertTrue(output.trim().endsWith(expectedOutput), "'$expectedOutput' should be printed but document text is:\n$output")
|
||||
}
|
||||
|
||||
private fun getReplOutput(
|
||||
maxIterations: Int = 50,
|
||||
sleepTime: Long = 500,
|
||||
textOnTimeOut: () -> String,
|
||||
predicate: () -> Boolean
|
||||
): String {
|
||||
for (i in 1..maxIterations) {
|
||||
UIUtil.dispatchAllInvocationEvents()
|
||||
if (predicate()) {
|
||||
return refreshAndGetHistoryEditorText()
|
||||
}
|
||||
Thread.sleep(sleepTime)
|
||||
}
|
||||
|
||||
return textOnTimeOut()
|
||||
}
|
||||
|
||||
private fun refreshAndGetHistoryEditorText(): String {
|
||||
val consoleView = consoleRunner.consoleView as LanguageConsoleImpl
|
||||
consoleView.flushDeferredText()
|
||||
|
||||
return consoleView.historyViewer.document.text
|
||||
}
|
||||
|
||||
private fun testSimpleCommand(command: String, expectedOutput: String) {
|
||||
sendCommand(command)
|
||||
checkOutput(expectedOutput)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRunPossibility() {
|
||||
val allOk = { x: String -> x.contains(":help for help") }
|
||||
val hasErrors = { x: String ->
|
||||
x.contains("Process finished with exit code 1") || x.contains("Exception in") || x.contains("Error")
|
||||
}
|
||||
|
||||
val output = getReplOutput(textOnTimeOut = { "Repl startup timed out" }) {
|
||||
val editorText = refreshAndGetHistoryEditorText()
|
||||
hasErrors(editorText) || allOk(editorText)
|
||||
}
|
||||
|
||||
assertFalse(hasErrors(output), "Cannot run kotlin repl")
|
||||
assertTrue(allOk(output), "Successful run should contain text: ':help for help'")
|
||||
assertFalse(consoleRunner.processHandler.isProcessTerminated, "Process accidentally terminated")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLongCommandLine() {
|
||||
ModuleRootModificationUtil.addDependency(module, createLibraryWithLongPaths(project))
|
||||
|
||||
consoleRunner.dispose()
|
||||
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
|
||||
|
||||
testRunPossibility()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnePlusOne() = testSimpleCommand("1 + 1", "2")
|
||||
|
||||
@Test
|
||||
fun testPrintlnText() = "Hello, console world!".let { testSimpleCommand("println(\"$it\")", it) }
|
||||
|
||||
@Test
|
||||
fun testDivisionByZeroException() = testSimpleCommand("1 / 0", "java.lang.ArithmeticException: / by zero")
|
||||
|
||||
@Test
|
||||
fun testMultilineSupport() {
|
||||
val printText = "Print in multiline!"
|
||||
|
||||
sendCommand(
|
||||
"fun f() {\n" +
|
||||
" println(\"$printText\")\n" +
|
||||
"}\n"
|
||||
)
|
||||
sendCommand("f()")
|
||||
|
||||
checkOutput(printText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReadLineSingle() {
|
||||
val readLineText = "ReadMe!"
|
||||
|
||||
sendCommand("val a = readLine()")
|
||||
sendCommand(readLineText)
|
||||
sendCommand("a")
|
||||
checkOutput(readLineText)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testReadLineMultiple() {
|
||||
val readLineTextA = "ReadMe A!"
|
||||
val readLineTextB = "ReadMe B!"
|
||||
|
||||
sendCommand(
|
||||
"val a = readLine()\n" +
|
||||
"val b = readLine()"
|
||||
)
|
||||
sendCommand(readLineTextA)
|
||||
sendCommand(readLineTextB)
|
||||
|
||||
sendCommand("a")
|
||||
checkOutput(readLineTextA)
|
||||
sendCommand("b")
|
||||
checkOutput(readLineTextB)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCorrectAfterError() {
|
||||
val message = "MyMessage"
|
||||
sendCommand("fun f() { println(x)\n println(y) ")
|
||||
sendCommand("println(\"$message\")")
|
||||
checkOutput(message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMultipleErrorsHandling() {
|
||||
val veryLongTextWithErrors = "println($);".repeat(30)
|
||||
sendCommand(veryLongTextWithErrors)
|
||||
sendCommand(veryLongTextWithErrors)
|
||||
sendCommand(veryLongTextWithErrors)
|
||||
sendCommand("println(\"OK\")")
|
||||
checkOutput("OK")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.stubs
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleType
|
||||
import com.intellij.openapi.module.StdModuleTypes
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||
import com.intellij.openapi.roots.ui.configuration.libraryEditor.NewLibraryEditor
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.jetbrains.kotlin.config.CompilerSettings
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettings
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
|
||||
import org.jetbrains.kotlin.idea.facet.initializeIfNeeded
|
||||
import org.jetbrains.kotlin.idea.test.*
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.kotlin.test.WithMutedInDatabaseRunTest
|
||||
import org.jetbrains.kotlin.test.runTest
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
|
||||
@WithMutedInDatabaseRunTest
|
||||
abstract class AbstractMultiModuleTest : DaemonAnalyzerTestCase() {
|
||||
|
||||
abstract override fun getTestDataPath(): String
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
enableKotlinOfficialCodeStyle(project)
|
||||
VfsRootAccess.allowRootAccess(testRootDisposable, KotlinTestUtils.getHomeDirectory())
|
||||
}
|
||||
|
||||
fun module(name: String, jdk: TestJdkKind = TestJdkKind.MOCK_JDK, hasTestRoot: Boolean = false): Module {
|
||||
val srcDir = testDataPath + "${getTestName(true)}/$name"
|
||||
val moduleWithSrcRootSet = createModuleFromTestData(srcDir, name, StdModuleTypes.JAVA, true)
|
||||
if (hasTestRoot) {
|
||||
addRoot(
|
||||
moduleWithSrcRootSet,
|
||||
File(testDataPath + "${getTestName(true)}/${name}Test"),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
ConfigLibraryUtil.configureSdk(moduleWithSrcRootSet, PluginTestCaseBase.addJdk(testRootDisposable) { PluginTestCaseBase.jdk(jdk) })
|
||||
|
||||
return moduleWithSrcRootSet
|
||||
}
|
||||
|
||||
override fun tearDown() = runAll(
|
||||
ThrowableRunnable { disableKotlinOfficialCodeStyle(project) },
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
)
|
||||
|
||||
public override fun createModule(path: String, moduleType: ModuleType<*>): Module {
|
||||
return super.createModule(path, moduleType)
|
||||
}
|
||||
|
||||
override fun runTestRunnable(testRunnable: ThrowableRunnable<Throwable>) {
|
||||
runTest { super.runTestRunnable(testRunnable) }
|
||||
}
|
||||
|
||||
fun addRoot(module: Module, sourceDirInTestData: File, isTestRoot: Boolean, transformContainedFiles: ((File) -> Unit)? = null) {
|
||||
val tmpDir = createTempDirectory()
|
||||
|
||||
// Preserve original root name. This might be useful for later matching of copied files to original ones
|
||||
val tmpRootDir = File(tmpDir, sourceDirInTestData.name).also { it.mkdir() }
|
||||
|
||||
FileUtil.copyDir(sourceDirInTestData, tmpRootDir)
|
||||
|
||||
if (transformContainedFiles != null) {
|
||||
tmpRootDir.listFiles().forEach(transformContainedFiles)
|
||||
}
|
||||
|
||||
val virtualTempDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tmpRootDir)!!
|
||||
object : WriteCommandAction.Simple<Unit>(project) {
|
||||
override fun run() {
|
||||
virtualTempDir.refresh(false, isTestRoot)
|
||||
}
|
||||
}.execute().throwException()
|
||||
PsiTestUtil.addSourceRoot(module, virtualTempDir, isTestRoot)
|
||||
}
|
||||
|
||||
fun Module.addDependency(
|
||||
other: Module,
|
||||
dependencyScope: DependencyScope = DependencyScope.COMPILE,
|
||||
exported: Boolean = false
|
||||
): Module = this.apply { ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported) }
|
||||
|
||||
fun Module.addLibrary(
|
||||
jar: File,
|
||||
name: String = KotlinJdkAndLibraryProjectDescriptor.LIBRARY_NAME,
|
||||
kind: PersistentLibraryKind<*>? = null
|
||||
) {
|
||||
ConfigLibraryUtil.addLibrary(NewLibraryEditor().apply {
|
||||
this.name = name
|
||||
addRoot(VfsUtil.getUrlForLibraryRoot(jar), OrderRootType.CLASSES)
|
||||
}, this, kind)
|
||||
}
|
||||
|
||||
fun Module.enableMultiPlatform(additionalCompilerArguments: String = "") {
|
||||
createFacet()
|
||||
val facetSettings = KotlinFacetSettingsProvider.getInstance(project)?.getInitializedSettings(this)
|
||||
?: error("Facet settings are not found")
|
||||
|
||||
facetSettings.useProjectSettings = false
|
||||
facetSettings.compilerSettings = CompilerSettings().apply {
|
||||
additionalArguments += " -Xmulti-platform $additionalCompilerArguments"
|
||||
}
|
||||
}
|
||||
|
||||
fun Module.enableCoroutines() {
|
||||
createFacet()
|
||||
val facetSettings = KotlinFacetSettingsProvider.getInstance(project)?.getInitializedSettings(this)
|
||||
?: error("Facet settings are not found")
|
||||
|
||||
facetSettings.useProjectSettings = false
|
||||
facetSettings.coroutineSupport = LanguageFeature.State.ENABLED
|
||||
}
|
||||
|
||||
protected fun checkFiles(
|
||||
findFiles: () -> List<PsiFile>,
|
||||
check: () -> Unit
|
||||
) {
|
||||
var atLeastOneFile = false
|
||||
findFiles().forEach { file ->
|
||||
configureByExistingFile(file.virtualFile!!)
|
||||
atLeastOneFile = true
|
||||
check()
|
||||
}
|
||||
Assert.assertTrue(atLeastOneFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun Module.createFacet(
|
||||
platformKind: TargetPlatform? = null,
|
||||
useProjectSettings: Boolean = true
|
||||
) {
|
||||
createFacetWithAdditionalSetup(platformKind, useProjectSettings) { }
|
||||
}
|
||||
|
||||
fun Module.createMultiplatformFacetM1(
|
||||
platformKind: TargetPlatform? = null,
|
||||
useProjectSettings: Boolean = true,
|
||||
implementedModuleNames: List<String>,
|
||||
pureKotlinSourceFolders: List<String>
|
||||
) {
|
||||
createFacetWithAdditionalSetup(platformKind, useProjectSettings) {
|
||||
this.implementedModuleNames = implementedModuleNames
|
||||
this.pureKotlinSourceFolders = pureKotlinSourceFolders
|
||||
}
|
||||
}
|
||||
|
||||
fun Module.createMultiplatformFacetM3(
|
||||
platformKind: TargetPlatform? = null,
|
||||
useProjectSettings: Boolean = true,
|
||||
dependsOnModuleNames: List<String>,
|
||||
pureKotlinSourceFolders: List<String>
|
||||
) {
|
||||
createFacetWithAdditionalSetup(platformKind, useProjectSettings) {
|
||||
this.dependsOnModuleNames = dependsOnModuleNames
|
||||
this.isHmppEnabled = true
|
||||
this.pureKotlinSourceFolders = pureKotlinSourceFolders
|
||||
}
|
||||
}
|
||||
|
||||
private fun Module.createFacetWithAdditionalSetup(
|
||||
platformKind: TargetPlatform?,
|
||||
useProjectSettings: Boolean,
|
||||
additionalSetup: KotlinFacetSettings.() -> Unit
|
||||
) {
|
||||
WriteAction.run<Throwable> {
|
||||
val modelsProvider = IdeModifiableModelsProviderImpl(project)
|
||||
with(getOrCreateFacet(modelsProvider, useProjectSettings).configuration.settings) {
|
||||
initializeIfNeeded(
|
||||
this@createFacetWithAdditionalSetup,
|
||||
modelsProvider.getModifiableRootModel(this@createFacetWithAdditionalSetup),
|
||||
platformKind
|
||||
)
|
||||
additionalSetup()
|
||||
}
|
||||
modelsProvider.commit()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.j2k
|
||||
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.DEBUG_LOG_ENABLE_PerModulePackageCache
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractJavaToKotlinConverterTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
project.DEBUG_LOG_ENABLE_PerModulePackageCache = true
|
||||
|
||||
val testName = getTestName(false)
|
||||
if (testName.contains("Java8") || testName.contains("java8")) {
|
||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_1_8
|
||||
}
|
||||
|
||||
VfsRootAccess.allowRootAccess(getTestRootDisposable(), KotlinTestUtils.getHomeDirectory())
|
||||
|
||||
invalidateLibraryCache(project)
|
||||
|
||||
addFile("KotlinApi.kt", "kotlinApi")
|
||||
addFile("JavaApi.java", "javaApi")
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
project.DEBUG_LOG_ENABLE_PerModulePackageCache = false
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
protected fun addFile(fileName: String, dirName: String? = null) {
|
||||
addFile(File("j2k/testData/$fileName"), dirName)
|
||||
}
|
||||
|
||||
protected fun addFile(file: File, dirName: String?): VirtualFile {
|
||||
return addFile(FileUtil.loadFile(file, true), file.name, dirName)
|
||||
}
|
||||
|
||||
protected fun addFile(text: String, fileName: String, dirName: String?): VirtualFile {
|
||||
return runWriteAction {
|
||||
val root = LightPlatformTestCase.getSourceRoot()!!
|
||||
val virtualDir = dirName?.let {
|
||||
root.findChild(it) ?: root.createChildDirectory(null, it)
|
||||
} ?: root
|
||||
val virtualFile = virtualDir.createChildData(null, fileName)
|
||||
virtualFile.getOutputStream(null)!!.writer().use { it.write(text) }
|
||||
virtualFile
|
||||
}
|
||||
}
|
||||
|
||||
protected fun deleteFile(virtualFile: VirtualFile) {
|
||||
runWriteAction { virtualFile.delete(this) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||
package org.jetbrains.kotlin.js.engine
|
||||
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
|
||||
|
||||
Reference in New Issue
Block a user