From 4718fd94b4d0878c591d0edeaade90ede4220756 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 3 Mar 2018 14:52:29 +0300 Subject: [PATCH] vcs: add tests for LineStatusTrackerManager --- .../vcs/impl/LineStatusTrackerManager.kt | 44 ++- .../vcs/BaseLineStatusTrackerManagerTest.kt | 261 ++++++++++++++++ .../vcs/BaseLineStatusTrackerTestCase.kt | 150 +++------ .../vcs/LineStatusTrackerManagerTest.kt | 285 ++++++++++++++++++ .../LineStatusTrackerModifyDocumentTest.kt | 14 +- .../vcs/LineStatusTrackerRevertAutoTest.kt | 6 +- .../vcs/PartialLineStatusTrackerTest.kt | 144 ++++----- 7 files changed, 716 insertions(+), 188 deletions(-) create mode 100644 platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerManagerTest.kt create mode 100644 platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt index 2fc28a0c2313..07b9e691143e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.kt @@ -61,11 +61,10 @@ import com.intellij.openapi.wm.ToolWindowManager import com.intellij.testFramework.LightVirtualFile import com.intellij.util.EventDispatcher import com.intellij.util.concurrency.AppExecutorUtil +import com.intellij.util.concurrency.Semaphore +import com.intellij.util.ui.UIUtil import com.intellij.vcsUtil.VcsUtil -import org.jetbrains.annotations.CalledInAny -import org.jetbrains.annotations.CalledInAwt -import org.jetbrains.annotations.CalledInBackground -import org.jetbrains.annotations.NonNls +import org.jetbrains.annotations.* import java.nio.charset.Charset import java.util.* @@ -956,6 +955,43 @@ class LineStatusTrackerManager( }) } } + + + @TestOnly + fun waitUntilBaseContentsLoaded() { + val semaphore = Semaphore() + semaphore.down() + + loader.addAfterUpdateRunnable(Runnable { + semaphore.up() + }) + + val start = System.currentTimeMillis() + while (true) { + if (ApplicationManager.getApplication().isDispatchThread) { + UIUtil.dispatchAllInvocationEvents() + } + if (semaphore.waitFor(10)) { + return + } + if (System.currentTimeMillis() - start > 2000) { + throw IllegalStateException("Couldn't await base contents") + } + } + } + + @TestOnly + fun releaseAllTrackers() { + synchronized(LOCK) { + forcedDocuments.clear() + + for (data in trackers.values) { + unregisterTrackerInCLM(data) + data.tracker.release() + } + trackers.clear() + } + } } diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerManagerTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerManagerTest.kt new file mode 100644 index 000000000000..04a55cccb91c --- /dev/null +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerManagerTest.kt @@ -0,0 +1,261 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.vcs + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.editor.Document +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.Project +import com.intellij.openapi.vcs.BaseLineStatusTrackerTestCase.Companion.parseInput +import com.intellij.openapi.vcs.changes.* +import com.intellij.openapi.vcs.changes.committed.MockAbstractVcs +import com.intellij.openapi.vcs.ex.LineStatusTracker +import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker +import com.intellij.openapi.vcs.ex.Range +import com.intellij.openapi.vcs.impl.LineStatusTrackerManager +import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl +import com.intellij.openapi.vcs.impl.projectlevelman.AllVcses +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.testFramework.LightPlatformTestCase +import com.intellij.testFramework.RunAll +import com.intellij.util.ThrowableRunnable +import com.intellij.vcsUtil.VcsUtil + +abstract class BaseLineStatusTrackerManagerTest : LightPlatformTestCase() { + protected lateinit var vcs: MyMockVcs + protected lateinit var changeProvider: MyMockChangeProvider + + protected lateinit var clm: ChangeListManagerImpl + protected lateinit var lstm: LineStatusTrackerManager + protected lateinit var dirtyScopeManager: VcsDirtyScopeManagerImpl + + protected lateinit var testRoot: VirtualFile + + protected lateinit var vcsManager: ProjectLevelVcsManagerImpl + + protected var arePartialChangelistsSupported: Boolean = true + + override fun setUp() { + super.setUp() + testRoot = runWriteAction { + VfsUtil.markDirtyAndRefresh(false, false, true, ourProject.baseDir) + VfsUtil.createDirectoryIfMissing(ourProject.baseDir, getTestName(true)) + } + + vcs = MyMockVcs(ourProject) + changeProvider = MyMockChangeProvider() + vcs.changeProvider = changeProvider + + clm = ChangeListManagerImpl.getInstanceImpl(ourProject) + lstm = LineStatusTrackerManager.getInstanceImpl(ourProject) + dirtyScopeManager = VcsDirtyScopeManager.getInstance(ourProject) as VcsDirtyScopeManagerImpl + + vcsManager = ProjectLevelVcsManager.getInstance(ourProject) as ProjectLevelVcsManagerImpl + vcsManager.registerVcs(vcs) + vcsManager.directoryMappings = listOf(VcsDirectoryMapping(testRoot.path, vcs.name)) + vcsManager.waitForInitialized() + assertTrue(vcsManager.hasActiveVcss()) + + try { + resetTestState() + } + catch (e: Throwable) { + super.tearDown() + throw e + } + } + + override fun tearDown() { + RunAll() + .append(ThrowableRunnable { resetChanges() }) + .append(ThrowableRunnable { resetChangelists() }) + .append(ThrowableRunnable { resetSettings() }) + .append(ThrowableRunnable { lstm.releaseAllTrackers() }) + .append(ThrowableRunnable { vcsManager.directoryMappings = emptyList() }) + .append(ThrowableRunnable { AllVcses.getInstance(ourProject).unregisterManually(vcs) }) + .append(ThrowableRunnable { runWriteAction { testRoot.delete(this) } }) + .append(ThrowableRunnable { super.tearDown() }) + .run() + } + + protected fun resetTestState() { + resetChanges() + resetChangelists() + resetSettings() + resetTestRootContent() + } + + private fun resetTestRootContent() { + VfsUtil.markDirtyAndRefresh(false, true, true, testRoot) + runWriteAction { testRoot.children.forEach { child -> child.delete(this) } } + } + + private fun resetSettings() { + VcsApplicationSettings.getInstance().ENABLE_PARTIAL_CHANGELISTS = true + VcsApplicationSettings.getInstance().SHOW_LST_GUTTER_MARKERS = true + VcsApplicationSettings.getInstance().SHOW_WHITESPACES_IN_LST = true + arePartialChangelistsSupported = true + } + + private fun resetChanges() { + changeProvider.changes.clear() + changeProvider.files.clear() + clm.waitUntilRefreshed() + } + + private fun resetChangelists() { + clm.addChangeList(LocalChangeList.DEFAULT_NAME, null) + clm.setDefaultChangeList(LocalChangeList.DEFAULT_NAME) + for (changeListName in clm.changeLists.map { it.name }) { + if (changeListName != LocalChangeList.DEFAULT_NAME) clm.removeChangeList(changeListName) + } + clm.waitUntilRefreshed() + } + + + protected fun addLocalFile(name: String, content: String): VirtualFile { + val file = runWriteAction { + val file = testRoot.createChildData(this, name) + VfsUtil.saveText(file, parseInput(content)) + file + } + + assertFalse(changeProvider.files.contains(file)) + changeProvider.files.add(file) + return file + } + + protected fun removeLocalFile(name: String) { + val file = runWriteAction { + val file = VfsUtil.findRelativeFile(testRoot, name) + file!!.delete(this) + file + } + + assertTrue(changeProvider.files.contains(file)) + changeProvider.files.remove(file) + } + + protected fun setBaseVersion(name: String, baseContent: String?) { + val filePath = VcsUtil.getFilePath(testRoot, name) + + val contentRevision: ContentRevision? = when (baseContent) { + null -> null + else -> SimpleContentRevision(parseInput(baseContent), filePath, "HEAD") + } + + changeProvider.changes[filePath] = contentRevision + } + + protected fun removeBaseVersion(name: String) { + val filePath = VcsUtil.getFilePath(testRoot, name) + changeProvider.changes.remove(filePath) + } + + protected fun refreshCLM() { + dirtyScopeManager.markEverythingDirty() + clm.scheduleUpdate() + clm.waitUntilRefreshed() + } + + protected fun releaseUnneededTrackers() { + runWriteAction { } // LineStatusTrackerManager.MyApplicationListener.afterWriteActionFinished + } + + + protected val VirtualFile.change: Change? get() = clm.getChange(this) + protected val VirtualFile.tracker: LineStatusTracker<*>? get() = lstm.getLineStatusTracker(this) + protected val VirtualFile.document: Document get() = FileDocumentManager.getInstance().getDocument(this)!! + protected fun VirtualFile.withOpenedEditor(task: () -> Unit) { + lstm.requestTrackerFor(document, this) + try { + task() + } + finally { + lstm.releaseTrackerFor(document, this) + } + } + protected open fun runCommand(task: () -> Unit) { + CommandProcessor.getInstance().executeCommand(getProject(), { + ApplicationManager.getApplication().runWriteAction(task) + }, "", null) + } + + protected fun String.asListNameToList(): LocalChangeList = clm.changeLists.find { it.name == this }!! + protected fun String.asListNameToId(): String = asListNameToList().id + protected fun Array.asListNamesToIds() = this.map { it.asListNameToId() } + private fun changeListsNames() = clm.changeLists.map { it.name } + + protected fun PartialLocalLineStatusTracker.assertAffectedChangeLists(vararg expectedNames: String) { + assertSameElements(this.affectedChangeListsIds, expectedNames.asListNamesToIds()) + } + + protected fun Range.assertChangeList(listName: String) { + val localRange = this as PartialLocalLineStatusTracker.LocalRange + assertEquals(localRange.changelistId, listName.asListNameToId()) + } + + + protected fun createChangelist(listName: String) { + assertDoesntContain(changeListsNames(), listName) + clm.addChangeList(listName, null) + } + + protected fun removeChangeList(listName: String) { + assertContainsElements(changeListsNames(), listName) + clm.removeChangeList(listName) + } + + protected fun setDefaultChangeList(listName: String) { + clm.setDefaultChangeList(listName) + } + + protected fun VirtualFile.moveChanges(fromListName: String, toListName: String) { + assertContainsElements(changeListsNames(), fromListName) + assertContainsElements(changeListsNames(), toListName) + val listChange = fromListName.asListNameToList().changes.find { it == this.change!! }!! + clm.moveChangesTo(toListName.asListNameToList(), listChange) + } + + protected fun VirtualFile.moveAllChangesTo(toListName: String) { + assertContainsElements(changeListsNames(), toListName) + clm.moveChangesTo(toListName.asListNameToList(), this.change!!) + } + + + protected class MyMockChangeProvider : ChangeProvider { + val changes = mutableMapOf() + val files = mutableSetOf() + + override fun getChanges(dirtyScope: VcsDirtyScope, + builder: ChangelistBuilder, + progress: ProgressIndicator, + addGate: ChangeListManagerGate) { + for ((filePath, beforeRevision) in changes) { + val file = files.find { VcsUtil.getFilePath(it) == filePath } + val afterContent: ContentRevision? = when (file) { + null -> null + else -> CurrentContentRevision(filePath) + } + + val change = Change(beforeRevision, afterContent) + + builder.processChange(change, MockAbstractVcs.getKey()) + } + } + + override fun isModifiedDocumentTrackingRequired(): Boolean { + return false + } + + override fun doCleanup(files: List) { + } + } + + protected inner class MyMockVcs(project: Project) : MockAbstractVcs(project) { + override fun arePartialChangelistsSupported(): Boolean = arePartialChangelistsSupported + } +} \ No newline at end of file diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt index 72c82fff985a..21e09e1929b1 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/BaseLineStatusTrackerTestCase.kt @@ -20,9 +20,7 @@ import com.intellij.diff.comparison.iterables.DiffIterableUtil.fair import com.intellij.diff.tools.util.text.LineOffsetsUtil import com.intellij.diff.util.DiffUtil import com.intellij.diff.util.Side -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runWriteAction -import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.impl.DocumentImpl import com.intellij.openapi.fileEditor.FileDocumentManager @@ -30,29 +28,25 @@ import com.intellij.openapi.fileTypes.PlainTextFileType import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vcs.changes.ChangeListManagerImpl -import com.intellij.openapi.vcs.changes.LocalChangeList import com.intellij.openapi.vcs.ex.* import com.intellij.openapi.vcs.ex.LineStatusTracker.Mode import com.intellij.openapi.vfs.VirtualFile -import com.intellij.testFramework.LightPlatformTestCase import com.intellij.testFramework.LightPlatformTestCase.assertOrderedEquals import com.intellij.testFramework.LightVirtualFile import com.intellij.util.containers.ContainerUtil import java.util.* -private typealias DiffRange = com.intellij.diff.util.Range - -abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { +abstract class BaseLineStatusTrackerTestCase : BaseLineStatusTrackerManagerTest() { protected fun test(text: String, task: Test.() -> Unit) { test(text, text, false, task) } protected fun test(text: String, vcsText: String, smart: Boolean = false, task: Test.() -> Unit) { - val mode = if (smart) Mode.SMART else Mode.DEFAULT - doTest(text, vcsText, - { document, file -> SimpleLocalLineStatusTracker.createTracker(getProject(), document, file, mode) }, - { tracker -> Test(tracker) }, - task) + resetTestState() + VcsApplicationSettings.getInstance().SHOW_WHITESPACES_IN_LST = smart + arePartialChangelistsSupported = false + + doTest(text, vcsText, { tracker -> Test(tracker as SimpleLocalLineStatusTracker) }, task) } protected fun testPartial(text: String, task: PartialTest.() -> Unit) { @@ -60,32 +54,43 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { } protected fun testPartial(text: String, vcsText: String, task: PartialTest.() -> Unit) { - doTest(text, vcsText, - { document, file -> PartialLocalLineStatusTracker.createTracker(getProject(), document, file, Mode.SMART) }, - { tracker -> PartialTest(tracker) }, - task) + resetTestState() + + doTest(text, vcsText, { tracker -> PartialTest(tracker as PartialLocalLineStatusTracker) }, task) } - protected fun , TestHelper : Test> doTest(text: String, vcsText: String, - createTracker: (Document, VirtualFile) -> Tracker, - createTestHelper: (Tracker) -> TestHelper, - task: TestHelper.() -> Unit) { + private fun doTest(text: String, vcsText: String, + createTestHelper: (LineStatusTracker<*>) -> TestHelper, + task: TestHelper.() -> Unit) { + val fileName = "file.txt" + val file = addLocalFile(fileName, parseInput(text)) + setBaseVersion(fileName, parseInput(vcsText)) + refreshCLM() + + file.withOpenedEditor { + lstm.waitUntilBaseContentsLoaded() + + val testHelper = createTestHelper(file.tracker!!) + testHelper.verify() + task(testHelper) + testHelper.verify() + } + } + + protected fun lightTest(text: String, vcsText: String, smart: Boolean = false, task: Test.() -> Unit) { val file = LightVirtualFile("LSTTestFile", PlainTextFileType.INSTANCE, parseInput(text)) val document = FileDocumentManager.getInstance().getDocument(file)!! val tracker = runWriteAction { - val tracker = createTracker(document, file) + val tracker = SimpleLocalLineStatusTracker.createTracker(getProject(), document, file, if (smart) Mode.SMART else Mode.DEFAULT) tracker.setBaseRevision(parseInput(vcsText)) tracker } try { - val testHelper = createTestHelper(tracker) + val testHelper = Test(tracker) testHelper.verify() - task(testHelper) - testHelper.verify() - testHelper.destroy() } finally { tracker.release() @@ -93,15 +98,12 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { } - protected open class Test(val tracker: LineStatusTracker<*>) { + protected open inner class Test(val tracker: LineStatusTracker<*>) { val file: VirtualFile = tracker.virtualFile val document: Document = tracker.document val vcsDocument: Document = tracker.vcsDocument private val documentTracker = tracker.getDocumentTrackerInTestMode() - open fun destroy() { - } - fun assertHelperContentIs(expected: String, helper: PartialLocalLineStatusTracker.PartialCommitHelper) { assertEquals(parseInput(expected), helper.content) } @@ -129,36 +131,33 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { } - fun runCommand(task: () -> Unit) { - CommandProcessor.getInstance().executeCommand(getProject(), { - ApplicationManager.getApplication().runWriteAction(task) - }, "", null) - + fun runCommandVerify(task: () -> Unit) { + this@BaseLineStatusTrackerTestCase.runCommand(task) verify() } fun insertAtStart(text: String) { - runCommand { document.insertString(0, parseInput(text)) } + runCommandVerify { document.insertString(0, parseInput(text)) } } fun TestRange.insertBefore(text: String) { - runCommand { document.insertString(this.start, parseInput(text)) } + runCommandVerify { document.insertString(this.start, parseInput(text)) } } fun TestRange.insertAfter(text: String) { - runCommand { document.insertString(this.end, parseInput(text)) } + runCommandVerify { document.insertString(this.end, parseInput(text)) } } fun TestRange.delete() { - runCommand { document.deleteString(this.start, this.end) } + runCommandVerify { document.deleteString(this.start, this.end) } } fun TestRange.replace(text: String) { - runCommand { document.replaceString(this.start, this.end, parseInput(text)) } + runCommandVerify { document.replaceString(this.start, this.end, parseInput(text)) } } fun replaceWholeText(text: String) { - runCommand { document.replaceString(0, document.textLength, parseInput(text)) } + runCommandVerify { document.replaceString(0, document.textLength, parseInput(text)) } } fun stripTrailingSpaces() { @@ -171,7 +170,7 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { } fun rollbackLines(lines: BitSet) { - runCommand { tracker.rollbackChanges(lines) } + runCommandVerify { tracker.rollbackChanges(lines) } } @@ -198,7 +197,7 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { operator fun Int.not(): Helper = Helper(this) operator fun Helper.minus(end: Int): TestRange = TestRange(this.start, end) - class Helper(val start: Int) + inner class Helper(val start: Int) infix fun String.at(range: TestRange): TestRange { assertEquals(parseInput(this), range.text) @@ -273,7 +272,7 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { } fun Range.rollback() { - runCommand { + runCommandVerify { tracker.rollbackChanges(this) } } @@ -373,68 +372,22 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { private fun getCurrentLines(range: Range): List = DiffUtil.getLines(document, range.line1, range.line2) } - protected class PartialTest(val partialTracker: PartialLocalLineStatusTracker) : Test(partialTracker) { + protected inner class PartialTest(val partialTracker: PartialLocalLineStatusTracker) : Test(partialTracker) { private val clm = ChangeListManagerImpl.getInstanceImpl(getProject()) - init { - resetChangelists() - partialTracker.initChangeTracking(defaultChangeListIds(), changeListIds(), null) + + fun assertAffectedChangeLists(vararg expected: String) { + partialTracker.assertAffectedChangeLists(*expected) } - override fun destroy() { - resetChangelists() - } - - private fun resetChangelists() { - clm.addChangeList(LocalChangeList.DEFAULT_NAME, null) - clm.setDefaultChangeList(LocalChangeList.DEFAULT_NAME) - for (changeListName in changeListNames()) { - if (changeListName != LocalChangeList.DEFAULT_NAME) clm.removeChangeList(changeListName) - } - } - - - fun assertAffectedChangelists(vararg expected: String) { - assertSameElements(partialTracker.affectedChangeListsIds, expected.toListId()) - } - - fun Range.assertChangelist(list: String) { - val localRange = this as PartialLocalLineStatusTracker.LocalRange - assertEquals(localRange.changelistId, list.toListId()) - } - - - fun createChangelist(list: String) { - assertDoesntContain(changeListNames(), list) + fun createChangeList_SetDefault(list: String) { clm.addChangeList(list, null) - } - - fun removeChangelist(list: String) { - assertContainsElements(changeListNames(), list) - partialTracker.changeListRemoved(list.toListId()) - clm.removeChangeList(list) - } - - fun setDefaultChangelist(list: String) { - clm.addChangeList(list, null) - partialTracker.defaultListChanged(defaultChangeListIds(), list.toListId()) clm.setDefaultChangeList(list) } fun handlePartialCommit(side: Side, list: String): PartialLocalLineStatusTracker.PartialCommitHelper { - return partialTracker.handlePartialCommit(side, listOf(list.toListId())) - } - - fun moveChanges(fromList: String, toList: String) { - assertContainsElements(changeListNames(), fromList) - assertContainsElements(changeListNames(), toList) - partialTracker.moveChanges(fromList.toListId(), toList.toListId()) - } - - fun moveAllChangesTo(toList: String) { - assertContainsElements(changeListNames(), toList) - partialTracker.moveChangesTo(toList.toListId()) + return partialTracker.handlePartialCommit(side, listOf(list.asListNameToId())) } @@ -447,13 +400,6 @@ abstract class BaseLineStatusTrackerTestCase : LightPlatformTestCase() { val changeList = clm.addChangeList(list, null) partialTracker.moveToChangelist(lines, changeList) } - - - fun String.toListId(): String = clm.changeLists.find { it.name == this }!!.id - private fun Array.toListId() = this.map { it.toListId() } - private fun changeListIds() = clm.changeLists.map { it.id } - private fun changeListNames() = clm.changeLists.map { it.name } - private fun defaultChangeListIds() = clm.defaultChangeList.id } companion object { diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt new file mode 100644 index 000000000000..3de9176784c3 --- /dev/null +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerManagerTest.kt @@ -0,0 +1,285 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.openapi.vcs + +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.ex.PartialLocalLineStatusTracker +import com.intellij.openapi.vcs.ex.SimpleLocalLineStatusTracker + +class LineStatusTrackerManagerTest : BaseLineStatusTrackerManagerTest() { + private val FILE_1 = "file1.txt" + private val FILE_2 = "file2.txt" + + fun `test mock changes`() { + setBaseVersion(FILE_1, "oldText") + refreshCLM() + assertEquals(1, clm.allChanges.size) + assertEquals(Change.Type.DELETED, clm.allChanges.first().type) + + addLocalFile(FILE_1, "text") + setBaseVersion(FILE_1, null) + refreshCLM() + assertEquals(1, clm.allChanges.size) + assertEquals(Change.Type.NEW, clm.allChanges.first().type) + + setBaseVersion(FILE_1, "oldText") + refreshCLM() + assertEquals(1, clm.allChanges.size) + assertEquals(Change.Type.MODIFICATION, clm.allChanges.first().type) + + removeLocalFile(FILE_1) + refreshCLM() + assertEquals(1, clm.allChanges.size) + assertEquals(Change.Type.DELETED, clm.allChanges.first().type) + + removeBaseVersion(FILE_1) + refreshCLM() + assertEquals(0, clm.allChanges.size) + + setBaseVersion(FILE_1, "oldText") + setBaseVersion(FILE_2, "oldText") + refreshCLM() + assertEquals(2, clm.allChanges.size) + } + + fun `test partial tracker lifecycle - editor for unchanged file`() { + createChangelist("Test") + val file = addLocalFile(FILE_1, "a_b_c_d_e") + assertNull(file.tracker) + + file.withOpenedEditor { + val tracker = file.tracker + assertNotNull(tracker) + assertTrue(tracker is SimpleLocalLineStatusTracker) + } + assertNull(file.tracker) + } + + fun `test partial tracker lifecycle - editor for modified file`() { + createChangelist("Test") + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b1_c_d1_e") + refreshCLM() + assertNull(file.tracker) + + file.withOpenedEditor { + val tracker = file.tracker + assertNotNull(tracker) + assertTrue(tracker is PartialLocalLineStatusTracker) + } + assertNotNull(file.tracker) + + lstm.waitUntilBaseContentsLoaded() + assertNull(file.tracker) + + file.withOpenedEditor { + val tracker = file.tracker + assertNotNull(tracker) + assertTrue(tracker is PartialLocalLineStatusTracker) + + lstm.waitUntilBaseContentsLoaded() + assertNotNull(file.tracker) + } + assertNull(file.tracker) + } + + fun `test partial tracker lifecycle - multiple editors`() { + createChangelist("Test") + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b1_c_d1_e") + refreshCLM() + assertNull(file.tracker) + + val requester1 = Any() + val requester2 = Any() + + lstm.requestTrackerFor(file.document, requester1) + assertNotNull(file.tracker) + + lstm.waitUntilBaseContentsLoaded() + lstm.requestTrackerFor(file.document, requester2) + assertNotNull(file.tracker) + + lstm.releaseTrackerFor(file.document, requester1) + assertNotNull(file.tracker) + + lstm.releaseTrackerFor(file.document, requester2) + assertNull(file.tracker) + } + + fun `test partial tracker lifecycle - with partial changes without editor`() { + createChangelist("Test") + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b1_c_d1_e") + refreshCLM() + assertNull(file.tracker) + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + + val ranges = tracker.getRanges()!! + assertEquals(2, ranges.size) + tracker.moveToChangelist(ranges[0], "Test".asListNameToList()) + tracker.assertAffectedChangeLists("Default", "Test") + } + assertNotNull(file.tracker) + + clm.waitUntilRefreshed() + releaseUnneededTrackers() + assertNotNull(file.tracker) + + file.moveAllChangesTo("Test") + clm.waitUntilRefreshed() + releaseUnneededTrackers() // partial tracker is not released immediately after becoming redundant + assertNull(file.tracker) + } + + fun `test tracker from non-default changelist`() { + createChangelist("Test") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b1_c_d1_e") + refreshCLM() + + file.moveAllChangesTo("Test") + clm.waitUntilRefreshed() + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + + tracker.assertAffectedChangeLists("Test") + } + } + + fun `test tracker from non-default changelist - modified during initialisation`() { + createChangelist("Test") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b_c_d1_e") + refreshCLM() + + file.moveAllChangesTo("Test") + clm.waitUntilRefreshed() + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + runCommand { tracker.document.replaceString(0, 1, "a2") } + + lstm.waitUntilBaseContentsLoaded() + + tracker.assertAffectedChangeLists("Test", "Default") + } + } + + fun `test tracker changes moves`() { + createChangelist("Test #1") + createChangelist("Test #2") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b1_c_d1_e") + refreshCLM() + + file.moveAllChangesTo("Test #2") + assertNull(file.tracker) + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + assertEquals(2, tracker.getRanges()!!.size) + tracker.assertAffectedChangeLists("Test #2") + + file.moveAllChangesTo("Test #1") + tracker.assertAffectedChangeLists("Test #1") + + tracker.moveToChangelist(tracker.getRanges()!![0], "Test #2".asListNameToList()) + tracker.assertAffectedChangeLists("Test #1", "Test #2") + + file.moveChanges("Test #2", "Default") + tracker.assertAffectedChangeLists("Test #1", "Default") + + file.moveAllChangesTo("Test #2") + tracker.assertAffectedChangeLists("Test #2") + } + } + + fun `test tracker changes moves - empty tracker`() { + createChangelist("Test #1") + createChangelist("Test #2") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b_c_d_e") + refreshCLM() + + file.moveAllChangesTo("Test #2") + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + lstm.waitUntilBaseContentsLoaded() + assertEquals(0, tracker.getRanges()!!.size) + tracker.assertAffectedChangeLists("Test #2") + + file.moveAllChangesTo("Test #1") + tracker.assertAffectedChangeLists("Test #1") + + file.moveAllChangesTo("Test #2") + tracker.assertAffectedChangeLists("Test #2") + + runCommand { tracker.document.replaceString(0, 1, "a2") } + tracker.assertAffectedChangeLists("Default") + } + } + + fun `test tracker changes moves - before initialisation`() { + createChangelist("Test") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b_c_d_e") + refreshCLM() + file.moveAllChangesTo("Test") + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + + tracker.assertAffectedChangeLists("Test") + + runCommand { tracker.document.replaceString(0, 1, "a2") } + tracker.assertAffectedChangeLists("Default", "Test") + + runCommand { tracker.document.replaceString(0, 2, "a") } + tracker.assertAffectedChangeLists("Test") + + assertFalse(tracker.isOperational()) + assertNull(tracker.getRanges()) + + lstm.waitUntilBaseContentsLoaded() + assertEquals(0, tracker.getRanges()!!.size) + tracker.assertAffectedChangeLists("Test") + } + } + + fun `test tracker changes moves - before initialisation 2`() { + createChangelist("Test") + + val file = addLocalFile(FILE_1, "a_b_c_d_e") + setBaseVersion(FILE_1, "a_b_c_d_e2") + refreshCLM() + file.moveAllChangesTo("Test") + + file.withOpenedEditor { + val tracker = file.tracker as PartialLocalLineStatusTracker + + tracker.assertAffectedChangeLists("Test") + + runCommand { tracker.document.replaceString(0, 1, "a2") } + tracker.assertAffectedChangeLists("Default", "Test") + + assertFalse(tracker.isOperational()) + assertNull(tracker.getRanges()) + + lstm.waitUntilBaseContentsLoaded() + assertEquals(2, tracker.getRanges()!!.size) + tracker.assertAffectedChangeLists("Default", "Test") + } + } +} \ No newline at end of file diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerModifyDocumentTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerModifyDocumentTest.kt index 962c2714a275..68868f4f8864 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerModifyDocumentTest.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerModifyDocumentTest.kt @@ -664,12 +664,12 @@ class LineStatusTrackerModifyDocumentTest : BaseLineStatusTrackerTestCase() { tracker.doFrozen(Runnable { assertNull(tracker.getRanges()) - runCommand { + runCommandVerify { document.setText("") document.setText("Y") } - runCommand { + runCommandVerify { document.setText("X\nX\nX\nX") } @@ -687,12 +687,12 @@ class LineStatusTrackerModifyDocumentTest : BaseLineStatusTrackerTestCase() { tracker.doFrozen(Runnable { assertNull(tracker.getRanges()) - runCommand { + runCommandVerify { document.setText("") document.setText("Y") } - runCommand { + runCommandVerify { document.setText(parseInput("Y_X_X_X_X")) } @@ -711,7 +711,7 @@ class LineStatusTrackerModifyDocumentTest : BaseLineStatusTrackerTestCase() { assertNull(tracker.getRanges()) tracker.doFrozen(Runnable { - runCommand { + runCommandVerify { document.setText("") document.setText("Y") } @@ -720,7 +720,7 @@ class LineStatusTrackerModifyDocumentTest : BaseLineStatusTrackerTestCase() { }) assertNull(tracker.getRanges()) - runCommand { + runCommandVerify { document.setText("X\nX\nX\nX") } @@ -740,7 +740,7 @@ class LineStatusTrackerModifyDocumentTest : BaseLineStatusTrackerTestCase() { tracker.setBaseRevision(parseInput("X_X_X_Z_Z")) - runCommand { + runCommandVerify { document.setText(parseInput("Y_X_X_X_X_Z_Z")) } diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerRevertAutoTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerRevertAutoTest.kt index 2599a7bdb631..c08d4a554b86 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerRevertAutoTest.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/LineStatusTrackerRevertAutoTest.kt @@ -63,13 +63,13 @@ class LineStatusTrackerRevertAutoTest : BaseLineStatusTrackerTestCase() { if (i % 1000 == 0) LOG.debug(i.toString()) try { val initial = generateText(textLength) - test(initial, initial, smart) { + lightTest(initial, initial, smart) { // println("Initial: " + initial.replace("\n", "\\n")); val count = myRng.nextInt(modifications) for (j in 0 until count) { val writeChanges = myRng.nextInt(4) + 1 - runCommand { + runCommandVerify { for (k in 0 until writeChanges) { applyRandomChange(changeLength) } @@ -110,7 +110,7 @@ class LineStatusTrackerRevertAutoTest : BaseLineStatusTrackerTestCase() { try { val initial = generateText(textLength) val initialVcs = generateText(textLength) - test(initial, initialVcs, smart) { + lightTest(initial, initialVcs, smart) { checkRevert(tracker.getRanges()!!.size * 2) } diff --git a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/PartialLineStatusTrackerTest.kt b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/PartialLineStatusTrackerTest.kt index 881e7750e56a..61d1dff22f92 100644 --- a/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/PartialLineStatusTrackerTest.kt +++ b/platform/vcs-tests/testSrc/com/intellij/openapi/vcs/PartialLineStatusTrackerTest.kt @@ -11,8 +11,8 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") } } @@ -20,19 +20,19 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") + range().assertChangeList("Default") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") "12".insertBefore("X_Y_Z") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") "3456".replace("X_Y_Z") - range(0).assertChangelist("Default") - range(1).assertChangelist("Test") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Default") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Default", "Test") } } @@ -40,24 +40,24 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") "56".insertAfter("b") - range(0).assertChangelist("Default") - range(1).assertChangelist("Test") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Default") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Default", "Test") "2345".insertAfter("c") - range().assertChangelist("Test") - assertAffectedChangelists("Test") + range().assertChangeList("Test") + assertAffectedChangeLists("Test") } } @@ -65,24 +65,24 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") "56".insertAfter("b") - range(0).assertChangelist("Default") - range(1).assertChangelist("Test") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Default") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Default", "Test") "2345_".delete() - range().assertChangelist("Test") - assertAffectedChangelists("Test") + range().assertChangeList("Test") + assertAffectedChangeLists("Test") } } @@ -90,14 +90,14 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") createChangelist("Test") range().moveTo("Test") - range().assertChangelist("Test") - assertAffectedChangelists("Test") + range().assertChangeList("Test") + assertAffectedChangeLists("Test") } } @@ -105,31 +105,31 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") "56".insertAfter("b") - range(0).assertChangelist("Default") - range(1).assertChangelist("Test") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Default") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Default", "Test") range(0).moveTo("Test") - range(0).assertChangelist("Test") - range(1).assertChangelist("Test") - assertAffectedChangelists("Test") + range(0).assertChangeList("Test") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Test") range(1).moveTo("Default") - range(0).assertChangelist("Test") - range(1).assertChangelist("Default") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Test") + range(1).assertChangeList("Default") + assertAffectedChangeLists("Default", "Test") } } @@ -137,25 +137,25 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("1234_2345_3456") { "12".insertAfter("a") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") - range().assertChangelist("Default") - assertAffectedChangelists("Default") + range().assertChangeList("Default") + assertAffectedChangeLists("Default") "56".insertAfter("b") - range(0).assertChangelist("Default") - range(1).assertChangelist("Test") - assertAffectedChangelists("Default", "Test") + range(0).assertChangeList("Default") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Default", "Test") - removeChangelist("Default") + removeChangeList("Default") - range(0).assertChangelist("Test") - range(1).assertChangelist("Test") - assertAffectedChangelists("Test") + range(0).assertChangeList("Test") + range(1).assertChangeList("Test") + assertAffectedChangeLists("Test") } } @@ -184,7 +184,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { testPartial("A_ _C_D_E_") { "A".replace("C_D_E") - setDefaultChangelist("Test") + createChangeList_SetDefault("Test") (2 th "C_D_E_").delete() assertTextContentIs("C_D_E_ _") @@ -203,7 +203,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default", "Test") + assertAffectedChangeLists("Default", "Test") val helper = handlePartialCommit(Side.LEFT, "Test") helper.applyChanges() @@ -211,7 +211,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertHelperContentIs("A_B_C_E_F_G_N_H_", helper) assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_E_F_G_N_H_") - assertAffectedChangelists("Default") + assertAffectedChangeLists("Default") } } @@ -226,7 +226,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default", "Test") + assertAffectedChangeLists("Default", "Test") val helper = handlePartialCommit(Side.LEFT, "Default") helper.applyChanges() @@ -234,7 +234,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertHelperContentIs("A_B1_C_D_E_F_M_G_H_", helper) assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B1_C_D_E_F_M_G_H_") - assertAffectedChangelists("Test") + assertAffectedChangeLists("Test") } } @@ -249,7 +249,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default", "Test") + assertAffectedChangeLists("Default", "Test") val helper = handlePartialCommit(Side.RIGHT, "Test") helper.applyChanges() @@ -257,7 +257,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertHelperContentIs("A_B1_C_D_E_F_M_G_H_", helper) assertTextContentIs("A_B1_C_D_E_F_M_G_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default") + assertAffectedChangeLists("Default") } } @@ -272,10 +272,10 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default", "Test") + assertAffectedChangeLists("Default", "Test") tracker.doFrozen(Runnable { - runCommand { + runCommandVerify { "B1_".replace("X_Y_Z_") val helper = handlePartialCommit(Side.LEFT, "Default") @@ -284,7 +284,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertHelperContentIs("A_X_Y_Z_C_D_E_F_M_G_H_", helper) assertTextContentIs("A_X_Y_Z_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_X_Y_Z_C_D_E_F_M_G_H_") - assertAffectedChangelists("Test") + assertAffectedChangeLists("Test") } }) } @@ -301,10 +301,10 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertTextContentIs("A_B1_C_E_F_M_G_N_H_") assertBaseTextContentIs("A_B_C_D_E_F_G_H_") - assertAffectedChangelists("Default", "Test") + assertAffectedChangeLists("Default", "Test") tracker.doFrozen(Runnable { - runCommand { + runCommandVerify { "B1_".replace("X_Y_Z_") val helper = handlePartialCommit(Side.LEFT, "Default") @@ -321,7 +321,7 @@ class PartialLineStatusTrackerTest : BaseLineStatusTrackerTestCase() { assertHelperContentIs("A_X_Y_Z_C_D_E_F_M_G_H_", helper) assertTextContentIs("A_X_Y_Z_C_E_F_M2_G_N2_H_") assertBaseTextContentIs("A_X_Y_Z_C_D_E_F_M_G_H_") - assertAffectedChangelists("Test") + assertAffectedChangeLists("Test") } }) }