From e2f9eaa483c887bad794352447f17d5038766512 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Fri, 27 Sep 2019 10:33:49 +0200 Subject: [PATCH] Use async profiler for perfTests if it presents in env variable; Add kt project copy-n-paste perfTests --- idea/build.gradle.kts | 2 +- .../perf/AbstractPerformanceProjectsTest.kt | 133 ++++- .../AbstractPerformanceProjectsTest.kt.193 | 551 ------------------ .../idea/perf/PerformanceProjectsTest.kt | 18 +- .../org/jetbrains/kotlin/idea/perf/Stats.kt | 95 ++- .../idea/perf/profilers/PhaseProfiler.kt | 32 + .../profilers/{async => }/ProfilerHandler.kt | 3 +- .../profilers/async/AsyncProfilerHandler.kt | 6 +- .../kotlin/idea/testFramework/Fixture.kt | 67 ++- 9 files changed, 258 insertions(+), 649 deletions(-) delete mode 100644 idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt.193 create mode 100644 idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt rename idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/{async => }/ProfilerHandler.kt (91%) diff --git a/idea/build.gradle.kts b/idea/build.gradle.kts index b67d9b38d26..debc12d7d11 100644 --- a/idea/build.gradle.kts +++ b/idea/build.gradle.kts @@ -201,7 +201,7 @@ projectTest(taskName = "performanceTest") { dependsOn(performanceTestRuntime) testClassesDirs = sourceSets["performanceTest"].output.classesDirs - classpath = performanceTestRuntime + classpath = performanceTestRuntime + files("${System.getenv("ASYNC_PROFILER_HOME")}/build/async-profiler.jar") workingDir = rootDir jvmArgs?.removeAll { it.startsWith("-Xmx") } diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt index 72c8a36801a..3816dda59be 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt @@ -13,6 +13,7 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.ide.highlighter.ModuleFileType import com.intellij.ide.startup.impl.StartupManagerImpl import com.intellij.idea.IdeaTestApplication +import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.editor.EditorFactory @@ -102,6 +103,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty()) } finally { closeProject(project) + myApplication.setDataProvider(null) } } @@ -112,9 +114,10 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { ThrowableRunnable { if (myProject != null) { DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save - (StartupManager.getInstance(myProject!!) as StartupManagerImpl).checkCleared() - (DaemonCodeAnalyzer.getInstance(myProject!!) as DaemonCodeAnalyzerImpl).cleanupAfterTest() - closeProject(myProject!!) + (StartupManager.getInstance(project()) as StartupManagerImpl).checkCleared() + (DaemonCodeAnalyzer.getInstance(project()) as DaemonCodeAnalyzerImpl).cleanupAfterTest() + closeProject(project()) + myApplication.setDataProvider(null) myProject = null } }).run() @@ -230,6 +233,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { // close all project but last - we're going to return and use it further if (counter < warmUpIterations + iterations - 1) { closeProject(project) + myApplication.setDataProvider(null) } counter++ } @@ -253,6 +257,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { dispatchAllInvocationEvents() Fixture.enableAnnotatorsAndLoadDefinitions(project) + + myApplication.setDataProvider(TestDataProvider(project)) } return lastProject ?: error("unable to open project $name at $path") @@ -265,7 +271,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { refreshGradleProject(projectPath, project) - //ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(false) dispatchAllInvocationEvents() // WARNING: [VD] DO NOT SAVE PROJECT AS IT COULD PERSIST WRONG MODULES INFO @@ -286,7 +291,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { revertChangesAtTheEnd: Boolean = true, note: String = "" ) = perfTypeAndAutocomplete( - myProject!!, stats, fileName, marker, insertString, surroundItems, + project(), stats, fileName, marker, insertString, surroundItems, lookupElements = lookupElements, typeAfterMarker = typeAfterMarker, revertChangesAtTheEnd = revertChangesAtTheEnd, note = note ) @@ -313,11 +318,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { val editor = fixture.editor val initialText = editor.document.text - if (isAKotlinScriptFile(fileName)) { - runAndMeasure("update script dependencies for $fileName") { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project) - } - } + updateScriptDependenciesIfNeeded(fileName, fixture, project) val tasksIdx = editor.document.text.indexOf(marker) assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0) @@ -360,7 +361,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } commitAllDocuments() } - } + }, + profileEnabled = true ) } @@ -374,7 +376,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { revertChangesAtTheEnd: Boolean = true, note: String = "" ) = perfTypeAndHighlight( - myProject!!, stats, fileName, marker, insertString, surroundItems, + project(), stats, fileName, marker, insertString, surroundItems, typeAfterMarker = typeAfterMarker, revertChangesAtTheEnd = revertChangesAtTheEnd, note = note ) @@ -399,11 +401,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { val editor = fixture.editor val initialText = editor.document.text - if (isAKotlinScriptFile(fileName)) { - runAndMeasure("update script dependencies for $fileName") { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project) - } - } + updateScriptDependenciesIfNeeded(fileName, fixture, project) val tasksIdx = editor.document.text.indexOf(marker) assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0) @@ -442,10 +440,97 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { pair.second.revertChanges(revertChangesAtTheEnd, pair.first) } commitAllDocuments() - } + }, + profileEnabled = true ) } + fun perfCopyAndPaste( + stats: Stats, + sourceFileName: String, + sourceInitialMarker: String? = null, + sourceFinalMarker: String? = null, + targetFileName: String, + targetInitialMarker: String? = null, + targetFinalMarker: String? = null, + note: String = "" + ) = perfCopyAndPaste( + project(), stats, + sourceFileName, sourceInitialMarker, sourceFinalMarker, + targetFileName, targetInitialMarker, targetFinalMarker, + note + ) + + fun perfCopyAndPaste( + project: Project, + stats: Stats, + sourceFileName: String, + sourceInitialMarker: String? = null, + sourceFinalMarker: String? = null, + targetFileName: String, + targetInitialMarker: String? = null, + targetFinalMarker: String? = null, + note: String = "" + ) { + stats.perfTest, String>, Boolean>( + warmUpIterations = 8, + iterations = 15, + testName = "${notePrefix(note)}$sourceFileName", + setUp = { + val fixture1 = openFixture(project, sourceFileName) + val fixture2 = openFixture(project, targetFileName) + + val initialText2 = fixture2.document.text + + updateScriptDependenciesIfNeeded(sourceFileName, fixture1, project) + updateScriptDependenciesIfNeeded(sourceFileName, fixture2, project) + + fixture1.selectMarkers(sourceInitialMarker, sourceFinalMarker) + fixture2.selectMarkers(targetInitialMarker, targetFinalMarker) + + it.setUpValue = Pair(arrayOf(fixture1, fixture2), initialText2) + }, + test = { + it.setUpValue?.let { setUpValue -> + val fixture1 = setUpValue.first[0] + val fixture2 = setUpValue.first[1] + it.value = fixture1.performEditorAction(IdeActions.ACTION_COPY) && + fixture2.performEditorAction(IdeActions.ACTION_PASTE) + } + }, + tearDown = { + try { + commitAllDocuments() + it.value?.let { performed -> + assertTrue("copy-n-paste has not performed well", performed) + // files could be different due to spaces + //assertEquals(it.setUpValue!!.first.document.text, it.setUpValue!!.second.document.text) + } + } finally { + it.setUpValue?.let { setUpValue -> + // pair.second.performEditorAction(IdeActions.ACTION_UNDO) + val fixture2 = setUpValue.first[1] + fixture2.applyText(setUpValue.second) + } + commitAllDocuments() + } + }, + profileEnabled = true + ) + } + + private fun updateScriptDependenciesIfNeeded( + fileName: String, + fixture: Fixture, + project: Project + ) { + if (isAKotlinScriptFile(fileName)) { + runAndMeasure("update script dependencies for $fileName") { + ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project) + } + } + } + private fun initKotlinProject( project: Project, projectPath: String, @@ -468,7 +553,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } protected fun perfHighlightFile(name: String, stats: Stats): List = - perfHighlightFile(myProject!!, name, stats) + perfHighlightFile(project(), name, stats) protected fun perfHighlightFile( project: Project, @@ -495,7 +580,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { commitAllDocuments() FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile) PsiManager.getInstance(project).dropPsiCaches() - } + }, + profileEnabled = !isWarmUp ) highlightInfos } @@ -517,7 +603,9 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } protected fun perfScriptDependencies(name: String, stats: Stats, note: String = "") = - perfScriptDependencies(myProject!!, name, stats, note = note) + perfScriptDependencies(project(), name, stats, note = note) + + private fun project() = myProject ?: error("project has not been initialized") private fun perfScriptDependencies( project: Project, @@ -536,7 +624,8 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { tearDown = { it.setUpValue?.let { ef -> cleanupCaches(project, ef.psiFile.virtualFile) } it.value?.let { v -> assertNotNull(v) } - } + }, + profileEnabled = true ) } diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt.193 b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt.193 deleted file mode 100644 index 857894967fa..00000000000 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt.193 +++ /dev/null @@ -1,551 +0,0 @@ -/* - * 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.perf - -import com.intellij.codeInsight.daemon.* -import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl -import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.ide.highlighter.ModuleFileType -import com.intellij.ide.startup.impl.StartupManagerImpl -import com.intellij.idea.IdeaTestApplication -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.editor.EditorFactory -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl -import com.intellij.openapi.module.ModuleManager -import com.intellij.openapi.module.ModuleTypeId -import com.intellij.openapi.project.DumbService -import com.intellij.openapi.project.Project -import com.intellij.openapi.project.ex.ProjectManagerEx -import com.intellij.openapi.project.impl.ProjectImpl -import com.intellij.openapi.projectRoots.JavaSdk -import com.intellij.openapi.projectRoots.ProjectJdkTable -import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl -import com.intellij.openapi.roots.ProjectRootManager -import com.intellij.openapi.roots.ex.ProjectRootManagerEx -import com.intellij.openapi.startup.StartupManager -import com.intellij.openapi.vcs.changes.ChangeListManager -import com.intellij.openapi.vcs.changes.ChangeListManagerImpl -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.testFramework.* -import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl -import com.intellij.util.ArrayUtilRt -import com.intellij.util.ThrowableRunnable -import com.intellij.util.indexing.UnindexedFilesUpdater -import com.intellij.util.io.exists -import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles -import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager -import org.jetbrains.kotlin.idea.framework.KotlinSdkType -import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP -import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure -import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies -import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil -import org.jetbrains.kotlin.idea.test.invalidateLibraryCache -import org.jetbrains.kotlin.idea.testFramework.* -import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches -import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile -import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFileInEditor -import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture -import java.io.File -import java.nio.file.Paths - -abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { - - // myProject is not required for all potential perf test cases - protected var myProject: Project? = null - private lateinit var jdk18: Sdk - private lateinit var myApplication: IdeaTestApplication - - override fun isStressTest(): Boolean = true - - override fun isPerformanceTest(): Boolean = false - - override fun setUp() { - super.setUp() - - myApplication = IdeaTestApplication.getInstance() - runWriteAction { - val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx() - val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") { - jdkTableImpl.internalJdk.homeDirectory!!.parent.path - } else { - jdkTableImpl.internalJdk.homePath!! - } - - val javaSdk = JavaSdk.getInstance() - jdk18 = javaSdk.createJdk("1.8", homePath) - val internal = javaSdk.createJdk("IDEA jdk", homePath) - - val jdkTable = ProjectJdkTable.getInstance() - jdkTable.addJdk(jdk18, testRootDisposable) - jdkTable.addJdk(internal, testRootDisposable) - KotlinSdkType.setUpIfNeeded() - } - } - - protected fun warmUpProject(stats: Stats) { - val project = perfOpenHelloWorld(stats, WARM_UP) - try { - val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, WARM_UP) - assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty()) - } finally { - closeProject(project) - } - } - - override fun tearDown() { - commitAllDocuments() - RunAll( - ThrowableRunnable { super.tearDown() }, - ThrowableRunnable { - if (myProject != null) { - DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled = true // return default value to avoid unnecessary save - (StartupManager.getInstance(myProject!!) as StartupManagerImpl).checkCleared() - (DaemonCodeAnalyzer.getInstance(myProject!!) as DaemonCodeAnalyzerImpl).cleanupAfterTest() - closeProject(myProject!!) - myProject = null - } - }).run() - } - - fun simpleFilename(fileName: String): String { - val lastIndexOf = fileName.lastIndexOf('/') - return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName - } - - protected fun perfOpenKotlinProjectFast(stats: Stats) = - perfOpenKotlinProject(stats, fast = true) - - protected fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) { - myProject = innerPerfOpenProject("kotlin", stats = stats, path = "../perfTestProject", note = "", fast = fast) - } - - protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project = - innerPerfOpenProject("helloKotlin", stats, note, path = "idea/testData/perfTest/helloKotlin", simpleModule = true) - - protected fun innerPerfOpenProject( - name: String, - stats: Stats, - note: String, - path: String, - simpleModule: Boolean = false, - fast: Boolean = false - ): Project { - val projectPath = File(path).canonicalPath - - assertTrue("path $path does not exist, check README.md", File(projectPath).exists()) - - val warmUpIterations = if (fast) 0 else 1 - val iterations = if (fast) 1 else 3 - val projectManagerEx = ProjectManagerEx.getInstanceEx() - - var lastProject: Project? = null - var counter = 0 - - stats.perfTest( - warmUpIterations = warmUpIterations, - iterations = iterations, - testName = "open project${if (note.isNotEmpty()) " $note" else ""}", - test = { - val project = if (!simpleModule) { - val project = projectManagerEx.loadProject(Paths.get(path), name) - assertNotNull("project $name at $path is not loaded", project) - val projectRootManager = ProjectRootManager.getInstance(project!!) - - runWriteAction { - with(projectRootManager) { - projectSdk = jdk18 - } - } - assertTrue("project $name at $path is not opened", projectManagerEx.openProject(project)) - project - } else { - val project = projectManagerEx.loadAndOpenProject(projectPath)!! - initKotlinProject(project, projectPath, name) - project - } - - (project as ProjectImpl).registerComponentImplementation( - FileEditorManager::class.java, - FileEditorManagerImpl::class.java - ) - - dispatchAllInvocationEvents() - - with(StartupManager.getInstance(project) as StartupManagerImpl) { - ProjectRootManagerEx.getInstanceEx(project).markRootsForRefresh() - VirtualFileManager.getInstance().syncRefresh() - - runStartupActivities() - runPostStartupActivities() - } - - logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" } - - with(ChangeListManager.getInstance(project) as ChangeListManagerImpl) { - waitUntilRefreshed() - } - - it.value = project - }, - tearDown = { - it.value?.let { project -> - - runAndMeasure("refresh gradle project $name") { - refreshGradleProjectIfNeeded(projectPath, project) - } - - ApplicationManager.getApplication().executeOnPooledThread { - DumbService.getInstance(project).waitForSmartMode() - - for (module in getModulesWithKotlinFiles(project)) { - module.getAndCacheLanguageLevelByDependencies() - } - }.get() - - val modules = ModuleManager.getInstance(project).modules - assertTrue("project has to have at least one module", modules.isNotEmpty()) - - logMessage { "modules of $name: ${modules.map { m -> m.name }}" } - - lastProject = project - VirtualFileManager.getInstance().syncRefresh() - - runWriteAction { - project.save() - } - - logMessage { "project '$name' successfully opened" } - - // close all project but last - we're going to return and use it further - if (counter < warmUpIterations + iterations - 1) { - closeProject(project) - } - counter++ - } - } - ) - - // indexing - lastProject?.let { project -> - invalidateLibraryCache(project) - - CodeInsightTestFixtureImpl.ensureIndexesUpToDate(project) - - dispatchAllInvocationEvents() - - logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" } - - with(DumbService.getInstance(project)) { - queueTask(UnindexedFilesUpdater(project)) - completeJustSubmittedTasks() - } - dispatchAllInvocationEvents() - - Fixture.enableAnnotatorsAndLoadDefinitions(project) - } - - return lastProject ?: error("unable to open project $name at $path") - } - - private fun refreshGradleProjectIfNeeded(projectPath: String, project: Project) { - if (listOf("build.gradle.kts", "build.gradle").map { name -> Paths.get(projectPath, name).exists() }.find { e -> e } != true) return - - ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(true) - - refreshGradleProject(projectPath, project) - - //ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(false) - dispatchAllInvocationEvents() - - // WARNING: [VD] DO NOT SAVE PROJECT AS IT COULD PERSIST WRONG MODULES INFO - -// runInEdtAndWait { -// PlatformTestUtil.saveProject(project) -// } - } - - fun perfTypeAndAutocomplete( - stats: Stats, - fileName: String, - marker: String, - insertString: String, - surroundItems: String = "\n", - lookupElements: List, - typeAfterMarker: Boolean = true, - revertChangesAtTheEnd: Boolean = true, - note: String = "" - ) = perfTypeAndAutocomplete( - myProject!!, stats, fileName, marker, insertString, surroundItems, - lookupElements = lookupElements, typeAfterMarker = typeAfterMarker, - revertChangesAtTheEnd = revertChangesAtTheEnd, note = note - ) - - fun perfTypeAndAutocomplete( - project: Project, - stats: Stats, - fileName: String, - marker: String, - insertString: String, - surroundItems: String = "\n", - lookupElements: List, - typeAfterMarker: Boolean = true, - revertChangesAtTheEnd: Boolean = true, - note: String = "" - ) { - assertTrue("lookupElements has to be not empty", lookupElements.isNotEmpty()) - stats.perfTest, Array>( - warmUpIterations = 8, - iterations = 15, - testName = "typeAndAutocomplete ${notePrefix(note)}$fileName", - setUp = { - val fixture = openFixture(project, fileName) - val editor = fixture.editor - - val initialText = editor.document.text - if (isAKotlinScriptFile(fileName)) { - runAndMeasure("update script dependencies for $fileName") { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project) - } - } - - val tasksIdx = editor.document.text.indexOf(marker) - assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0) - if (typeAfterMarker) { - editor.caretModel.moveToOffset(tasksIdx + marker.length + 1) - } else { - editor.caretModel.moveToOffset(tasksIdx - 1) - } - - for (surroundItem in surroundItems) { - EditorTestUtil.performTypingAction(editor, surroundItem) - } - - editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2) - - if (!typeAfterMarker) { - for (surroundItem in surroundItems) { - EditorTestUtil.performTypingAction(editor, surroundItem) - } - editor.caretModel.moveToOffset(editor.caretModel.offset - 2) - } - - fixture.type(insertString) - - it.setUpValue = Pair(initialText, fixture) - }, - test = { - val fixture = it.setUpValue!!.second - it.value = fixture.complete() - }, - tearDown = { - val items = it.value?.map { e -> e.lookupString }?.toList() ?: emptyList() - try { - for (lookupElement in lookupElements) { - assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement)) - } - } finally { - it.setUpValue?.let { pair -> - pair.second.revertChanges(revertChangesAtTheEnd, pair.first) - } - commitAllDocuments() - } - } - ) - } - - fun perfTypeAndHighlight( - stats: Stats, - fileName: String, - marker: String, - insertString: String, - surroundItems: String = "\n", - typeAfterMarker: Boolean = true, - revertChangesAtTheEnd: Boolean = true, - note: String = "" - ) = perfTypeAndHighlight( - myProject!!, stats, fileName, marker, insertString, surroundItems, - typeAfterMarker = typeAfterMarker, - revertChangesAtTheEnd = revertChangesAtTheEnd, note = note - ) - - fun perfTypeAndHighlight( - project: Project, - stats: Stats, - fileName: String, - marker: String, - insertString: String, - surroundItems: String = "\n", - typeAfterMarker: Boolean = true, - revertChangesAtTheEnd: Boolean = true, - note: String = "" - ) { - stats.perfTest, List>( - warmUpIterations = 8, - iterations = 15, - testName = "typeAndHighlight ${notePrefix(note)}$fileName", - setUp = { - val fixture = openFixture(project, fileName) - val editor = fixture.editor - - val initialText = editor.document.text - if (isAKotlinScriptFile(fileName)) { - runAndMeasure("update script dependencies for $fileName") { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(fixture.psiFile, project) - } - } - - val tasksIdx = editor.document.text.indexOf(marker) - assertTrue("marker '$marker' not found in $fileName", tasksIdx > 0) - if (typeAfterMarker) { - editor.caretModel.moveToOffset(tasksIdx + marker.length + 1) - } else { - editor.caretModel.moveToOffset(tasksIdx - 1) - } - - for (surroundItem in surroundItems) { - EditorTestUtil.performTypingAction(editor, surroundItem) - } - - editor.caretModel.moveToOffset(editor.caretModel.offset - if (typeAfterMarker) 1 else 2) - - if (!typeAfterMarker) { - for (surroundItem in surroundItems) { - EditorTestUtil.performTypingAction(editor, surroundItem) - } - editor.caretModel.moveToOffset(editor.caretModel.offset - 2) - } - - fixture.type(insertString) - - it.setUpValue = Pair(initialText, fixture) - }, - test = { - val fixture = it.setUpValue!!.second - it.value = fixture.doHighlighting() - }, - tearDown = { - it.value?.let { list -> - assertNotEmpty(list) - } - it.setUpValue?.let { pair -> - pair.second.revertChanges(revertChangesAtTheEnd, pair.first) - } - commitAllDocuments() - } - ) - } - - private fun initKotlinProject( - project: Project, - projectPath: String, - name: String - ) { - val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}" - val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!! - val srcFile = projectFile.findChild("src")!! - val module = runWriteAction { - val projectRootManager = ProjectRootManager.getInstance(project) - with(projectRootManager) { - projectSdk = jdk18 - } - val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.newModule(modulePath, ModuleTypeId.JAVA_MODULE) - PsiTestUtil.addSourceRoot(module, srcFile) - module - } - ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk18) - } - - protected fun perfHighlightFile(name: String, stats: Stats): List = - perfHighlightFile(myProject!!, name, stats) - - protected fun perfHighlightFile( - project: Project, - fileName: String, - stats: Stats, - note: String = "" - ): List { - return highlightFile { - val isWarmUp = note == WARM_UP - var highlightInfos: List = emptyList() - stats.perfTest>( - warmUpIterations = if (isWarmUp) 1 else 3, - iterations = if (isWarmUp) 2 else 10, - testName = "highlighting ${notePrefix(note)}${simpleFilename(fileName)}", - setUp = { - it.setUpValue = openFileInEditor(project, fileName) - }, - test = { - val file = it.setUpValue - it.value = highlightFile(project, file!!.psiFile) - }, - tearDown = { - highlightInfos = it.value ?: emptyList() - commitAllDocuments() - FileEditorManager.getInstance(project).closeFile(it.setUpValue!!.psiFile.virtualFile) - PsiManager.getInstance(project).dropPsiCaches() - } - ) - highlightInfos - } - } - - fun highlightFile(block: () -> T): T { - var value: T? = null - IdentifierHighlighterPassFactory.doWithHighlightingEnabled { - value = block() - } - return value!! - } - - private fun highlightFile(project: Project, psiFile: PsiFile): List { - val document = FileDocumentManager.getInstance().getDocument(psiFile.virtualFile)!! - val editor = EditorFactory.getInstance().getEditors(document).first() - PsiDocumentManager.getInstance(project).commitAllDocuments() - return CodeInsightTestFixtureImpl.instantiateAndRun(psiFile, editor, ArrayUtilRt.EMPTY_INT_ARRAY, true) - } - - protected fun perfScriptDependencies(name: String, stats: Stats, note: String = "") = - perfScriptDependencies(myProject!!, name, stats, note = note) - - private fun perfScriptDependencies( - project: Project, - fileName: String, - stats: Stats, - note: String = "" - ) { - if (!isAKotlinScriptFile(fileName)) return - stats.perfTest( - testName = "updateScriptDependencies ${notePrefix(note)}${simpleFilename(fileName)}", - setUp = { it.setUpValue = openFileInEditor(project, fileName) }, - test = { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(it.setUpValue!!.psiFile, project) - it.value = it.setUpValue - }, - tearDown = { - it.setUpValue?.let { ef -> cleanupCaches(project, ef.psiFile.virtualFile) } - it.value?.let { v -> assertNotNull(v) } - } - ) - } - - fun notePrefix(note: String) = if (note.isNotEmpty()) { - if (note.endsWith("/")) note else "$note " - } else "" - - -} \ No newline at end of file diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt index 0a022984534..f20cf479687 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -102,6 +102,21 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { } } + fun testKotlinProjectCopyAndPaste() { + tcSuite("Kotlin copy-and-paste") { + val stats = Stats("Kotlin copy-and-paste") + stats.use { stat -> + perfOpenKotlinProjectFast(stat) + + perfCopyAndPaste( + stat, + sourceFileName = "compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt", + targetFileName = "compiler/psi/src/org/jetbrains/kotlin/psi/KtImportInfo.kt" + ) + } + } + } + fun testKotlinProjectCompletionKtFile() { tcSuite("Kotlin completion ktFile") { val stats = Stats("Kotlin completion ktFile") @@ -239,7 +254,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { testName = testName, setUp = perfKtsFileAnalysisSetUp(project, fileName), test = perfKtsFileAnalysisTest(), - tearDown = perfKtsFileAnalysisTearDown(extraTimingsNs, project) + tearDown = perfKtsFileAnalysisTearDown(extraTimingsNs, project), + profileEnabled = true ) extraStats.printWarmUpTimings( diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/Stats.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/Stats.kt index d77ba78636c..443572398de 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/Stats.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/Stats.kt @@ -6,8 +6,7 @@ package org.jetbrains.kotlin.idea.perf import org.jetbrains.kotlin.idea.perf.WholeProjectPerformanceTest.Companion.nsToMs -import org.jetbrains.kotlin.idea.perf.profilers.async.DummyProfilerHandler -import org.jetbrains.kotlin.idea.perf.profilers.async.ProfilerHandler +import org.jetbrains.kotlin.idea.perf.profilers.* import org.jetbrains.kotlin.idea.testFramework.logMessage import org.jetbrains.kotlin.util.PerformanceCounter import java.io.* @@ -19,7 +18,11 @@ import kotlin.test.assertEquals typealias StatInfos = Map? -class Stats(val name: String = "", val header: Array = arrayOf("Name", "ValueMS", "StdDev")) : Closeable { +class Stats( + val name: String = "", + val header: Array = arrayOf("Name", "ValueMS", "StdDev"), + val acceptanceStabilityLevel: Int = 25 +) : Closeable { private val perfTestRawDataMs = mutableListOf() @@ -49,7 +52,7 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " for (v in listOf( Triple("mean", "", calcMean.mean.toLong()), Triple("stdDev", " stdDev", calcMean.stdDev.toLong()), - Triple("geomMean", "geomMean", calcMean.geomMean.toLong()) + Triple("geomMean", " geomMean", calcMean.geomMean.toLong()) )) { val n = "$id : ${v.first}" @@ -63,7 +66,7 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " .fold(mutableSetOf(), { acc, keys -> acc.addAll(keys); acc }) .filter { it != TEST_KEY && it != ERROR_KEY } .sorted().forEach { perfCounterName -> - val values = statInfosArray.map { (it?.get(perfCounterName) as Long) }.toLongArray() + val values = statInfosArray.map { (it?.get(perfCounterName) as? Long) ?: 0L }.toLongArray() val statInfoMean = calcMean(values) val n = "$id : $perfCounterName" @@ -147,6 +150,23 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " assertEquals(iterations, statInfoArray.size) if (testName != WARM_UP) { appendTimings(testName, statInfoArray) + + // do not estimate stability for warm-up + if (!testName.contains(WARM_UP)) { + val calcMean = calcMean(statInfoArray) + val stabilityPercentage = round(calcMean.stdDev * 100.0 / calcMean.mean).toInt() + logMessage { "$testName stability is $stabilityPercentage %" } + val stabilityName = "$name: $testName stability" + + val stable = stabilityPercentage <= acceptanceStabilityLevel + printTestStarted(stabilityName) + printStatValue(stabilityName, stabilityPercentage) + if (stable) { + printTestFinished(stabilityName) + } else { + printTestFailed(stabilityName, "stability above $stabilityPercentage %") + } + } } } @@ -202,19 +222,8 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " warmUpStatInfosArray.filterNotNull().map { it[ERROR_KEY] as? Exception }.firstOrNull()?.let { throw it } } - private fun mainPhase(phaseData: PhaseData): Array { - val statInfosArray = phase(phaseData, "") - - // do not estimate stability for warm-up - if (!phaseData.testName.contains(WARM_UP)) { - val calcMean = calcMean(statInfosArray) - val stabilityPercentage = round(calcMean.stdDev * 100.0 / calcMean.mean).toInt() - logMessage { "${phaseData.testName} stability is $stabilityPercentage %" } - check(stabilityPercentage <= 10) { "${phaseData.testName} is not stable: stability above $stabilityPercentage %" } - } - - return statInfosArray - } + private fun mainPhase(phaseData: PhaseData): Array = + phase(phaseData, "") private fun phase(phaseData: PhaseData, phaseName: String): Array { val statInfosArray = Array(phaseData.iterations) { null } @@ -275,13 +284,13 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " val profilerHandler = if (phaseData.profileEnabled) ProfilerHandler.getInstance() else DummyProfilerHandler return if (profilerHandler != DummyProfilerHandler) { - val profilerPath = pathToResource("profile/${plainname()}/") + val profilerPath = pathToResource("profile/${plainname()}") check(with(File(profilerPath)) { exists() || mkdirs() }) { "unable to mkdirs $profilerPath for ${phaseData.testName}" } val activityName = "${phaseData.testName}-${if (phaseName.isEmpty()) "" else "$phaseName-"}$attempt" ActualPhaseProfiler(activityName, profilerPath, profilerHandler) } else { - dummyPhaseProfiler + DummyPhaseProfiler } } @@ -313,11 +322,6 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " const val WARM_UP = "warm-up" - private val dummyPhaseProfiler = object : PhaseProfiler { - override fun start() {} - override fun stop() {} - } - inline fun runAndMeasure(note: String, block: () -> Unit) { val openProjectMillis = measureTimeMillis { block() @@ -329,6 +333,14 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " println("##teamcity[testStarted name='$testName' captureStandardOutput='true']") } + fun printStatValue(name: String, value: Any) { + println("##teamcity[buildStatisticValue key='$name' value='$value']") + } + + private fun printTestFinished(testName: String) { + println("##teamcity[testFinished name='$testName']") + } + fun printTestFinished(testName: String, spentMs: Long, includeStatValue: Boolean = true) { if (includeStatValue) { printStatValue(testName, spentMs) @@ -336,16 +348,15 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " println("##teamcity[testFinished name='$testName' duration='$spentMs']") } - fun printStatValue(name: String, value: Any) { - println("##teamcity[buildStatisticValue key='$name' value='$value']") - } - fun printTestFinished(testName: String, error: Throwable) { println("error at $testName:") - tcPrintErrors(testName, listOf(error)) - printStatValue(testName, -1) - println("##teamcity[testFinished name='$testName']") + tcPrintErrors(testName, listOf(error)) + //printTestFinished(testName) + } + + private fun printTestFailed(testName: String, details: String) { + println("##teamcity[testFailed name='$testName' message='Exceptions reported' details='${tcEscape(details)}']") } inline fun tcSuite(name: String, block: () -> Unit) { @@ -361,7 +372,7 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " printTestStarted(name) val (time, errors) = block() tcPrintErrors(name, errors) - printTestFinished(name, time, includeStatValue = false) + //printTestFinished(name, time, includeStatValue = false) } private fun tcEscape(s: String) = s.replace("|", "||") @@ -381,27 +392,11 @@ class Stats(val name: String = "", val header: Array = arrayOf("Name", " } errorDetailsPrintWriter.close() val details = detailsWriter.toString() - println("##teamcity[testFailed name='$name' message='Exceptions reported' details='${tcEscape(details)}']") + printTestFailed(name, details) } } } - private interface PhaseProfiler { - fun start() - - fun stop() - } - - private class ActualPhaseProfiler(val activityName: String, val profilerPath: String, val profilerHandler: ProfilerHandler) : - PhaseProfiler { - override fun start() { - profilerHandler.startProfiling(activityName) - } - - override fun stop() { - profilerHandler.stopProfiling(profilerPath, activityName) - } - } } data class PhaseData( diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt new file mode 100644 index 00000000000..c3bbeb1918d --- /dev/null +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt @@ -0,0 +1,32 @@ +/* + * 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.perf.profilers + +interface PhaseProfiler { + fun start() + + fun stop() +} + +object DummyPhaseProfiler : PhaseProfiler { + override fun start() {} + override fun stop() {} +} + +class ActualPhaseProfiler( + private val activityName: String, + private val profilerPath: String, + private val profilerHandler: ProfilerHandler +) : + PhaseProfiler { + override fun start() { + profilerHandler.startProfiling(activityName) + } + + override fun stop() { + profilerHandler.stopProfiling(profilerPath, activityName) + } +} \ No newline at end of file diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/ProfilerHandler.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt similarity index 91% rename from idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/ProfilerHandler.kt rename to idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt index 522408d5701..b7ad56e16c4 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/ProfilerHandler.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt @@ -3,9 +3,10 @@ * 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.perf.profilers.async +package org.jetbrains.kotlin.idea.perf.profilers import com.intellij.openapi.util.SystemInfo +import org.jetbrains.kotlin.idea.perf.profilers.async.AsyncProfilerHandler import org.jetbrains.kotlin.idea.testFramework.logMessage interface ProfilerHandler { diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt index 9cba69f7950..e0f07c665db 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt @@ -8,8 +8,8 @@ package org.jetbrains.kotlin.idea.perf.profilers.async import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.util.containers.ContainerUtil +import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler import org.jetbrains.kotlin.idea.testFramework.logMessage -//import one.profiler.AsyncProfiler import java.io.File import java.nio.file.Files import java.nio.file.StandardCopyOption @@ -33,6 +33,7 @@ internal class AsyncProfilerHandler : ProfilerHandler { } private fun execute(command: String) { + logMessage { "asyncProfiler command: '$command'" } executeMethod.invoke(asyncProfiler, command) } @@ -49,7 +50,8 @@ internal class AsyncProfilerHandler : ProfilerHandler { override fun stopProfiling(snapshotsPath: String, activityName: String, options: List) { val combinedOptions = ArrayList(options) val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath) - val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(activityName, combinedOptions) + val name = activityName.replace(' ', '_').replace('/', '_') + val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions) for (stopCommand in stopAndDumpCommands) { execute(stopCommand) } diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/testFramework/Fixture.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/testFramework/Fixture.kt index 2d7472b6fb6..564c428f765 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/testFramework/Fixture.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/testFramework/Fixture.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx import com.intellij.openapi.project.Project import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.roots.FileIndexFacade @@ -35,10 +36,10 @@ import com.intellij.psi.search.FilenameIndex import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.xml.XmlFileNSInfoProvider import com.intellij.testFramework.EditorTestUtil -import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.fixtures.EditorTestFixture import com.intellij.testFramework.runInEdtAndWait import com.intellij.xml.XmlSchemaProvider +import junit.framework.TestCase.* import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager @@ -48,7 +49,7 @@ import org.jetbrains.kotlin.parsing.KotlinParserDefinition class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, val vFile: VirtualFile = psiFile.virtualFile) { - private val delegate = EditorTestFixture(project, editor, vFile) + private var delegate = EditorTestFixture(project, editor, vFile) val document: Document get() = editor.document @@ -59,26 +60,49 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va delegate.type(s) } + fun performEditorAction(actionId: String): Boolean { + selectEditor() + return delegate.performEditorAction(actionId) + } + fun complete(type: CompletionType = CompletionType.BASIC, invocationCount: Int = 1): Array = delegate.complete(type, invocationCount) ?: emptyArray() fun revertChanges(revertChangesAtTheEnd: Boolean, text: String) { try { if (revertChangesAtTheEnd) { - runWriteAction { - // TODO: [VD] revert ? - //editorFixture.performEditorAction(IdeActions.SELECTED_CHANGES_ROLLBACK) - document.setText(text) - saveDocument(document) - commitDocument(project, document) - } - dispatchAllInvocationEvents() + // TODO: [VD] revert ? + //editorFixture.performEditorAction(IdeActions.SELECTED_CHANGES_ROLLBACK) + applyText(text) } } finally { cleanupCaches(project, vFile) } } + fun selectMarkers(initialMarker: String?, finalMarker: String?) { + selectEditor() + val text = editor.document.text + editor.selectionModel.setSelection( + initialMarker?.let { marker -> text.indexOf(marker) } ?: 0, + finalMarker?.let { marker -> text.indexOf(marker) } ?: text.length) + } + + private fun selectEditor() { + val fileEditorManagerEx = FileEditorManagerEx.getInstanceEx(project) + fileEditorManagerEx.openFile(vFile, true) + check(fileEditorManagerEx.selectedEditor?.file == vFile) { "unable to open $vFile" } + } + + fun applyText(text: String) { + runWriteAction { + document.setText(text) + saveDocument(document) + commitDocument(project, document) + } + dispatchAllInvocationEvents() + } + companion object { // quite simple impl - good so far fun isAKotlinScriptFile(fileName: String) = fileName.endsWith(KotlinParserDefinition.STD_SCRIPT_EXT) @@ -112,15 +136,16 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va scriptDefinitionsManager.getAllDefinitions() dispatchAllInvocationEvents() - UsefulTestCase.assertTrue(scriptDefinitionsManager.isReady()) - UsefulTestCase.assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled) + assertTrue(scriptDefinitionsManager.isReady()) + assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled) } fun openFixture(project: Project, fileName: String): Fixture { val fileInEditor = openFileInEditor(project, fileName) val file = fileInEditor.psiFile - val editor = EditorFactory.getInstance().getEditors(fileInEditor.document, project)[0] + val editorFactory = EditorFactory.getInstance() + val editor = editorFactory.getEditors(fileInEditor.document, project)[0] return Fixture(project, editor, file) } @@ -148,7 +173,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va ) .filter { it.canonicalPath?.contains("/$projectBaseName/$name") ?: false }.toList() - UsefulTestCase.assertEquals( + assertEquals( "expected the only file with name '$name'\n, it were: [${virtualFiles.map { it.canonicalPath }.joinToString("\n")}]", 1, virtualFiles.size @@ -163,18 +188,18 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va val psiFile = projectFileByName(project, name) val vFile = psiFile.virtualFile - UsefulTestCase.assertTrue("file $vFile is not indexed yet", FileIndexFacade.getInstance(project).isInContent(vFile)) + assertTrue("file $vFile is not indexed yet", FileIndexFacade.getInstance(project).isInContent(vFile)) runInEdtAndWait { fileEditorManager.openFile(vFile, true) } - val document = fileDocumentManager.getDocument(vFile)!! + val document = fileDocumentManager.getDocument(vFile) ?: error("no document for $vFile found") - UsefulTestCase.assertNotNull("doc not found for $vFile", EditorFactory.getInstance().getEditors(document)) - UsefulTestCase.assertTrue("expected non empty doc", document.text.isNotEmpty()) + assertNotNull("doc not found for $vFile", EditorFactory.getInstance().getEditors(document)) + assertTrue("expected non empty doc", document.text.isNotEmpty()) val offset = psiFile.textOffset - UsefulTestCase.assertTrue("side effect: to load the text", offset >= 0) + assertTrue("side effect: to load the text", offset >= 0) waitForAllEditorsFinallyLoaded(project) @@ -204,7 +229,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va } val tasksIdx = fileInEditor.document.text.indexOf(marker) - UsefulTestCase.assertTrue(tasksIdx > 0) + assertTrue(tasksIdx > 0) editor.caretModel.moveToOffset(tasksIdx + marker.length + 1) for (surroundItem in surroundItems) { @@ -218,7 +243,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va val elements = fixture.complete() val items = elements.map { it.lookupString }.toList() for (lookupElement in lookupElements) { - UsefulTestCase.assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement)) + assertTrue("'$lookupElement' has to be present in items", items.contains(lookupElement)) } } } finally {