mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
508 lines
16 KiB
Kotlin
508 lines
16 KiB
Kotlin
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
|
package org.jetbrains.idea.svn
|
|
|
|
import com.intellij.openapi.Disposable
|
|
import com.intellij.openapi.command.WriteCommandAction.writeCommandAction
|
|
import com.intellij.openapi.util.Disposer
|
|
import com.intellij.openapi.util.io.FileUtil.toSystemDependentName
|
|
import com.intellij.openapi.vcs.FileStatus
|
|
import com.intellij.openapi.vcs.VcsConfiguration
|
|
import com.intellij.openapi.vcs.changes.Change
|
|
import com.intellij.openapi.vfs.VirtualFile
|
|
import com.intellij.testFramework.RunAll
|
|
import com.intellij.testFramework.TestLoggerFactory
|
|
import com.intellij.testFramework.UsefulTestCase.assertDoesntExist
|
|
import com.intellij.testFramework.UsefulTestCase.assertExists
|
|
import com.intellij.testFramework.runInEdtAndWait
|
|
import com.intellij.util.ThrowableRunnable
|
|
import org.hamcrest.CoreMatchers.allOf
|
|
import org.hamcrest.CoreMatchers.nullValue
|
|
import org.hamcrest.FeatureMatcher
|
|
import org.hamcrest.Matcher
|
|
import org.hamcrest.Matchers.*
|
|
import org.jetbrains.annotations.NonNls
|
|
import org.junit.Assert.*
|
|
import org.junit.Assume
|
|
import org.junit.Test
|
|
import java.io.File
|
|
import java.io.IOException
|
|
import java.nio.file.Paths
|
|
import kotlin.io.path.invariantSeparatorsPathString
|
|
|
|
@NonNls
|
|
private const val LOG_SEPARATOR_START = "-------------"
|
|
|
|
class SvnRenameTest : SvnTestCase() {
|
|
private var testRootDisposable: Disposable? = null
|
|
|
|
override fun before() {
|
|
super.before()
|
|
|
|
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
|
|
testRootDisposable = Disposer.newDisposable("SvnRenameTest")
|
|
TestLoggerFactory.enableDebugLogging(testRootDisposable!!,
|
|
"#com.intellij.openapi.command.impl",
|
|
"#com.intellij.history.integration.revertion.UndoChangeRevertingVisitor",
|
|
"#com.intellij.openapi.command.impl.ChangeRange",
|
|
"#com.intellij.openapi.command.impl.UndoableGroup")
|
|
}
|
|
|
|
override fun after() {
|
|
RunAll.runAll(
|
|
ThrowableRunnable<Throwable> {
|
|
testRootDisposable?.let { Disposer.dispose(it) }
|
|
testRootDisposable = null
|
|
},
|
|
ThrowableRunnable<Throwable> { super.after() }
|
|
)
|
|
}
|
|
|
|
@Test
|
|
fun testSimpleRename() {
|
|
val a = createFileInCommand("a.txt", "test")
|
|
checkin()
|
|
|
|
renameFileInCommand(a, "b.txt")
|
|
runAndVerifyStatus(
|
|
"D a.txt", "> moved to b.txt",
|
|
"A + b.txt", "> moved from a.txt"
|
|
)
|
|
}
|
|
|
|
// IDEADEV-18844
|
|
@Test
|
|
fun testRenameReplace() {
|
|
val a = createFileInCommand("a.txt", "old")
|
|
val aNew = createFileInCommand("aNew.txt", "new")
|
|
checkin()
|
|
|
|
renameFileInCommand(a, "aOld.txt")
|
|
renameFileInCommand(aNew, "a.txt")
|
|
runAndVerifyStatus(
|
|
"R + a.txt", "> moved to aOld.txt", "> moved from aNew.txt",
|
|
"D aNew.txt", "> moved to a.txt",
|
|
"A + aOld.txt", "> moved from a.txt"
|
|
)
|
|
}
|
|
|
|
// IDEADEV-16251
|
|
@Test
|
|
fun testRenameAddedPackage() {
|
|
val dir = createDirInCommand(myWorkingCopyDir, "child")
|
|
createFileInCommand(dir, "a.txt", "content")
|
|
renameFileInCommand(dir, "newchild")
|
|
runAndVerifyStatusSorted("A newchild", "A newchild/a.txt")
|
|
}
|
|
|
|
// IDEADEV-8091
|
|
@Test
|
|
fun testDoubleRename() {
|
|
val a = createFileInCommand("a.txt", "test")
|
|
checkin()
|
|
|
|
renameFileInCommand(a, "b.txt")
|
|
renameFileInCommand(a, "c.txt")
|
|
runAndVerifyStatus(
|
|
"D a.txt", "> moved to c.txt",
|
|
"A + c.txt", "> moved from a.txt"
|
|
)
|
|
}
|
|
|
|
// IDEADEV-15876
|
|
@Test
|
|
fun testRenamePackageWithChildren() {
|
|
val child = prepareDirectoriesForRename()
|
|
|
|
renameFileInCommand(child, "childnew")
|
|
runAndVerifyStatus(
|
|
"D child", "> moved to childnew",
|
|
"D child/a.txt",
|
|
"D child/grandChild",
|
|
"D child/grandChild/b.txt",
|
|
"A + childnew", "> moved from child"
|
|
)
|
|
|
|
refreshVfs() // wait for end of refresh operations initiated from SvnFileSystemListener
|
|
changeListManager.ensureUpToDate()
|
|
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", child.isValid)
|
|
assertChanges(
|
|
"child" to "childnew",
|
|
"child/a.txt" to "childnew/a.txt",
|
|
"child/grandChild" to "childnew/grandChild",
|
|
"child/grandChild/b.txt" to "childnew/grandChild/b.txt"
|
|
)
|
|
}
|
|
|
|
private fun prepareDirectoriesForRename(): VirtualFile {
|
|
val child = createDirInCommand(myWorkingCopyDir, "child")
|
|
val grandChild = createDirInCommand(child, "grandChild")
|
|
createFileInCommand(child, "a.txt", "a")
|
|
createFileInCommand(grandChild, "b.txt", "b")
|
|
checkin()
|
|
return child
|
|
}
|
|
|
|
// IDEADEV-19065
|
|
@Test
|
|
fun testCommitAfterRenameDir() {
|
|
val child = prepareDirectoriesForRename()
|
|
|
|
renameFileInCommand(child, "newchild")
|
|
checkin()
|
|
|
|
val runResult = runSvn("log", "-q", "newchild/a.txt")
|
|
verify(runResult)
|
|
val lines = runResult.stdout.lines().filterNot { it.isEmpty() || it.startsWith(LOG_SEPARATOR_START) }
|
|
assertThat(lines, contains(startsWith("r2 |"), startsWith("r1 |")))
|
|
}
|
|
|
|
// todo - undo; undo after commit
|
|
// IDEADEV-9755
|
|
@Test
|
|
fun testRollbackRenameDir() {
|
|
val child = prepareDirectoriesForRename()
|
|
renameFileInCommand(child, "newchild")
|
|
|
|
changeListManager.ensureUpToDate()
|
|
val change = changeListManager.getChange(myWorkingCopyDir.findChild("newchild")!!)
|
|
assertNotNull(change)
|
|
|
|
rollback(listOf(change))
|
|
assertDoesntExist(File(myWorkingCopyDir.path, "newchild"))
|
|
assertExists(File(myWorkingCopyDir.path, "child"))
|
|
}
|
|
|
|
// todo undo; undo after commit
|
|
// IDEADEV-7697
|
|
@Test
|
|
fun testMovePackageToParent() {
|
|
val child = createDirInCommand(myWorkingCopyDir, "child")
|
|
val grandChild = createDirInCommand(child, "grandChild")
|
|
createFileInCommand(grandChild, "a.txt", "a")
|
|
checkin()
|
|
moveFileInCommand(grandChild, myWorkingCopyDir)
|
|
refreshVfs() // wait for end of refresh operations initiated from SvnFileSystemListener
|
|
changeListManager.ensureUpToDate()
|
|
assertChanges("child/grandChild" to "grandChild", "child/grandChild/a.txt" to "grandChild/a.txt")
|
|
}
|
|
|
|
// IDEADEV-19223
|
|
@Test
|
|
fun testRollbackRenameWithUnversioned() {
|
|
val child = createDirInCommand(myWorkingCopyDir, "child")
|
|
createFileInCommand(child, "a.txt", "a")
|
|
checkin()
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val unversioned = createFileInCommand(child, "u.txt", "u")
|
|
val unversionedDir = createDirInCommand(child, "uc")
|
|
createFileInCommand(unversionedDir, "c.txt", "c")
|
|
|
|
changeListManager.ensureUpToDate()
|
|
assertEquals(FileStatus.UNKNOWN, changeListManager.getStatus(unversioned))
|
|
|
|
renameFileInCommand(child, "newchild")
|
|
val childPath = File(myWorkingCopyDir.path, "child")
|
|
val newChildPath = File(myWorkingCopyDir.path, "newchild")
|
|
assertExists(File(newChildPath, "a.txt"))
|
|
assertExists(File(newChildPath, "u.txt"))
|
|
assertDoesntExist(File(childPath, "u.txt"))
|
|
|
|
refreshVfs()
|
|
changeListManager.ensureUpToDate()
|
|
val changes = mutableListOf(
|
|
changeListManager.getChange(myWorkingCopyDir.findChild("newchild")!!.findChild("a.txt")!!)!!,
|
|
changeListManager.getChange(myWorkingCopyDir.findChild("newchild")!!)!!
|
|
)
|
|
|
|
rollback(changes)
|
|
assertExists(File(childPath, "a.txt"))
|
|
assertExists(File(childPath, "u.txt"))
|
|
assertExists(File(childPath, "uc"))
|
|
assertExists(File(childPath, "uc/c.txt"))
|
|
}
|
|
|
|
// IDEA-13824
|
|
@Test
|
|
fun testRenameFileRenameDir() {
|
|
val child = prepareDirectoriesForRename()
|
|
val f = child.findChild("a.txt")
|
|
renameFileInCommand(f, "anew.txt")
|
|
renameFileInCommand(child, "newchild")
|
|
|
|
runAndVerifyStatus(
|
|
"D child", "> moved to newchild",
|
|
"D child/a.txt",
|
|
"D child/grandChild",
|
|
"D child/grandChild/b.txt",
|
|
"A + newchild", "> moved from child",
|
|
"D + newchild/a.txt", "> moved to newchild/anew.txt",
|
|
"A + newchild/anew.txt", "> moved from newchild/a.txt"
|
|
)
|
|
|
|
refreshVfs() // wait for end of refresh operations initiated from SvnFileSystemListener
|
|
changeListManager.ensureUpToDate()
|
|
|
|
runAndVerifyStatus(
|
|
"D child", "> moved to newchild",
|
|
"D child/a.txt",
|
|
"D child/grandChild",
|
|
"D child/grandChild/b.txt",
|
|
"A + newchild", "> moved from child",
|
|
"D + newchild/a.txt", "> moved to newchild/anew.txt",
|
|
"A + newchild/anew.txt", "> moved from newchild/a.txt"
|
|
)
|
|
|
|
commit(changeListManager.defaultChangeList.changes.toList(), "test")
|
|
}
|
|
|
|
// IDEADEV-19364
|
|
@Test
|
|
fun testUndoMovePackage() {
|
|
val parent1 = createDirInCommand(myWorkingCopyDir, "parent1")
|
|
val parent2 = createDirInCommand(myWorkingCopyDir, "parent2")
|
|
val child = createDirInCommand(parent1, "child")
|
|
createFileInCommand(child, "a.txt", "a")
|
|
checkin()
|
|
|
|
moveFileInCommand(child, parent2)
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", child.isValid)
|
|
|
|
val childPath = File(parent1.path, "child")
|
|
assertExists(childPath)
|
|
assertExists(File(childPath, "a.txt"))
|
|
}
|
|
}
|
|
|
|
// IDEADEV-19552
|
|
@Test
|
|
fun testUndoRename() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
checkin()
|
|
|
|
renameFileInCommand(file, "b.txt")
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileRename()
|
|
assertExists(File(myWorkingCopyDir.path, "a.txt"))
|
|
assertDoesntExist(File(myWorkingCopyDir.path, "b.txt"))
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun testUndoCommittedRenameFile() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
checkin()
|
|
|
|
renameFileInCommand(file, "b.txt")
|
|
checkin()
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileRename()
|
|
runAndVerifyStatus(
|
|
"A + a.txt", "> moved from b.txt",
|
|
"D b.txt", "> moved to a.txt"
|
|
)
|
|
}
|
|
}
|
|
|
|
// IDEADEV-19336
|
|
@Test
|
|
fun testUndoMoveCommittedPackage() {
|
|
enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE)
|
|
val parent1 = createDirInCommand(myWorkingCopyDir, "parent1")
|
|
val parent2 = createDirInCommand(myWorkingCopyDir, "parent2")
|
|
val child = createDirInCommand(parent1, "child")
|
|
createFileInCommand(child, "a.txt", "a")
|
|
checkin()
|
|
|
|
moveFileInCommand(child, parent2)
|
|
checkin()
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", child.isValid)
|
|
|
|
runAndVerifyStatus(
|
|
"A + parent1/child", "> moved from parent2/child",
|
|
"D parent2/child", "> moved to parent1/child",
|
|
"D parent2/child/a.txt"
|
|
)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun testMoveToUnversioned() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
val child = moveToNewPackage(file, "child")
|
|
runAndVerifyStatusSorted("A child", "A child/a.txt")
|
|
checkin()
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val unversioned = createDirInCommand(myWorkingCopyDir, "unversioned")
|
|
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
|
|
moveFileInCommand(child, unversioned)
|
|
runAndVerifyStatusSorted("? unversioned", "D child", "D child/a.txt")
|
|
}
|
|
|
|
@Test
|
|
fun testUndoMoveToUnversioned() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
val child = moveToNewPackage(file, "child")
|
|
runAndVerifyStatusSorted("A child", "A child/a.txt")
|
|
checkin()
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val unversioned = createDirInCommand(myWorkingCopyDir, "unversioned")
|
|
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
|
|
moveFileInCommand(child, unversioned)
|
|
runAndVerifyStatusSorted("? unversioned", "D child", "D child/a.txt")
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", child.isValid)
|
|
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun testUndoMoveUnversionedToUnversioned() {
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
runAndVerifyStatusSorted("? a.txt")
|
|
val unversioned = createDirInCommand(myWorkingCopyDir, "unversioned")
|
|
moveFileInCommand(file, unversioned)
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", file.isValid)
|
|
|
|
runAndVerifyStatusSorted("? a.txt", "? unversioned")
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun testUndoMoveAddedToUnversioned() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
runAndVerifyStatusSorted("A a.txt")
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val unversioned = createDirInCommand(myWorkingCopyDir, "unversioned")
|
|
moveFileInCommand(file, unversioned)
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", file.isValid)
|
|
|
|
runAndVerifyStatusSorted("? a.txt", "? unversioned")
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun testUndoMoveToUnversionedCommitted() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
val child = moveToNewPackage(file, "child")
|
|
runAndVerifyStatusSorted("A child", "A child/a.txt")
|
|
checkin()
|
|
disableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
val unversioned = createDirInCommand(myWorkingCopyDir, "unversioned")
|
|
enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD)
|
|
runAndVerifyStatusSorted("? unversioned")
|
|
|
|
moveFileInCommand(child, unversioned)
|
|
runAndVerifyStatusSorted("? unversioned", "D child", "D child/a.txt")
|
|
checkin()
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", child.isValid)
|
|
|
|
runAndVerifyStatusSorted("? child", "? unversioned")
|
|
}
|
|
}
|
|
|
|
// IDEA-92941
|
|
@Test
|
|
fun testUndoNewMove() {
|
|
val sink = createDirInCommand(myWorkingCopyDir, "sink")
|
|
val child = createDirInCommand(myWorkingCopyDir, "child")
|
|
runAndVerifyStatusSorted("A child", "A sink")
|
|
checkin()
|
|
val file = createFileInCommand(child, "a.txt", "A")
|
|
runAndVerifyStatusSorted("A child/a.txt")
|
|
moveFileInCommand(file, sink)
|
|
runAndVerifyStatusSorted("A sink/a.txt")
|
|
|
|
makeVfsRefreshBehaveMaybe {
|
|
undoFileMove()
|
|
Assume.assumeTrue("Suspecting blinking IDEA-182560. Test aborted.", file.isValid)
|
|
|
|
runAndVerifyStatusSorted("A child/a.txt")
|
|
}
|
|
}
|
|
|
|
// todo undo, undo committed?
|
|
@Test
|
|
fun testMoveToNewPackage() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
moveToNewPackage(file, "child")
|
|
runAndVerifyStatusSorted("A child", "A child/a.txt")
|
|
}
|
|
|
|
@Test
|
|
fun testMoveToNewPackageCommitted() {
|
|
val file = createFileInCommand(myWorkingCopyDir, "a.txt", "A")
|
|
checkin()
|
|
moveToNewPackage(file, "child")
|
|
runAndVerifyStatus(
|
|
"D a.txt", "> moved to child/a.txt",
|
|
"A child",
|
|
"A + child/a.txt", "> moved from a.txt"
|
|
)
|
|
}
|
|
|
|
private fun moveToNewPackage(file: VirtualFile, packageName: String) =
|
|
writeCommandAction(myProject)
|
|
.withName("SvnRenameTest MoveToNewPackage") //NON-NLS
|
|
.compute<VirtualFile, IOException> {
|
|
val packageDirectory = myWorkingCopyDir.createChildDirectory(this, packageName)
|
|
file.move(this, packageDirectory)
|
|
packageDirectory
|
|
}
|
|
|
|
private fun assertChanges(vararg expected: Pair<String?, String?>) {
|
|
val changes = changeListManager.defaultChangeList.changes.toMutableList()
|
|
assertThat(changes, containsInAnyOrder(expected.map { changeMatcher(it) }))
|
|
}
|
|
|
|
private fun changeMatcher(paths: Pair<String?, String?>) = allOf(beforePathMatcher(paths.first), afterPathMatcher(paths.second))
|
|
|
|
private fun beforePathMatcher(beforePath: String?) =
|
|
object : FeatureMatcher<Change, String?>(pathMatcher(beforePath), "before path", "before path") {
|
|
override fun featureValueOf(actual: Change) = actual.beforeRevision?.file?.path
|
|
}
|
|
|
|
private fun afterPathMatcher(afterPath: String?) =
|
|
object : FeatureMatcher<Change, String?>(pathMatcher(afterPath), "after path", "after path") {
|
|
override fun featureValueOf(actual: Change) = actual.afterRevision?.file?.path
|
|
}
|
|
|
|
fun pathMatcher(path: String?): Matcher<in String?> = if (path == null) nullValue()
|
|
else equalToIgnoringCase(Paths.get(myWorkingCopyDir.path).resolve(toSystemDependentName(path)).invariantSeparatorsPathString)
|
|
|
|
/*
|
|
* Try to workaround IDEA-182560
|
|
*/
|
|
private fun makeVfsRefreshBehaveMaybe(runnable: () -> Unit) {
|
|
runInEdtAndWait(runnable)
|
|
}
|
|
}
|