mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[file-history] add file history tests
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
// 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.vcs.log.history
|
||||
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.openapi.vcs.FilePath
|
||||
import com.intellij.openapi.vcs.LocalFilePath
|
||||
import com.intellij.vcs.log.data.index.VcsLogPathsIndex
|
||||
import com.intellij.vcs.log.data.index.VcsLogPathsIndex.ChangeKind.*
|
||||
import com.intellij.vcs.log.graph.TestGraphBuilder
|
||||
import com.intellij.vcs.log.graph.TestPermanentGraphInfo
|
||||
import com.intellij.vcs.log.graph.api.LinearGraph
|
||||
import com.intellij.vcs.log.graph.asTestGraphString
|
||||
import com.intellij.vcs.log.graph.graph
|
||||
import com.intellij.vcs.log.graph.impl.facade.BaseController
|
||||
import com.intellij.vcs.log.graph.impl.facade.FilteredController
|
||||
import gnu.trove.TIntObjectHashMap
|
||||
import org.junit.Assert
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
|
||||
class FileHistoryTest {
|
||||
|
||||
fun LinearGraph.assert(startCommit: Int, startPath: FilePath, fileNamesData: FileNamesData, result: TestGraphBuilder.() -> Unit) {
|
||||
val permanentGraphInfo = TestPermanentGraphInfo(this)
|
||||
val baseController = BaseController(permanentGraphInfo)
|
||||
val filteredController = object : FilteredController(baseController, permanentGraphInfo, fileNamesData.getCommits()) {}
|
||||
|
||||
val historyBuilder = FileHistoryBuilder(startCommit, startPath, fileNamesData)
|
||||
historyBuilder.accept(filteredController, permanentGraphInfo)
|
||||
|
||||
val expectedResultGraph = graph(result)
|
||||
val actualResultGraph = filteredController.collapsedGraph.compiledGraph
|
||||
|
||||
Assert.assertEquals(expectedResultGraph.asTestGraphString(true), actualResultGraph.asTestGraphString(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun linearHistory() {
|
||||
val path = LocalFilePath("file.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(path)
|
||||
.addChange(path, 7, listOf(ADDED), listOf(7))
|
||||
.addChange(path, 6, listOf(MODIFIED), listOf(7))
|
||||
.addChange(path, 4, listOf(MODIFIED), listOf(5))
|
||||
.addChange(path, 2, listOf(REMOVED), listOf(3))
|
||||
.addChange(path, 0, listOf(ADDED), listOf(1))
|
||||
.build()
|
||||
|
||||
graph {
|
||||
0(1)
|
||||
1(2)
|
||||
2(3)
|
||||
3(4)
|
||||
4(5)
|
||||
5(6)
|
||||
6(7)
|
||||
7()
|
||||
}.assert(0, path, fileNamesData) {
|
||||
0(2.dot)
|
||||
2(4.dot)
|
||||
4(6.dot)
|
||||
6(7)
|
||||
7()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun historyWithRename() {
|
||||
val afterPath = LocalFilePath("after.txt", false)
|
||||
val beforePath = LocalFilePath("before.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(afterPath)
|
||||
.addChange(beforePath, 6, listOf(ADDED), listOf(7))
|
||||
.addChange(beforePath, 4, listOf(REMOVED), listOf(5))
|
||||
.addChange(afterPath, 4, listOf(ADDED), listOf(5))
|
||||
.addRename(5, 4, beforePath, afterPath)
|
||||
.addChange(afterPath, 2, listOf(MODIFIED), listOf(3))
|
||||
.build()
|
||||
|
||||
graph {
|
||||
0(1)
|
||||
1(2)
|
||||
2(3)
|
||||
3(4)
|
||||
4(5)
|
||||
5(6)
|
||||
6(7)
|
||||
7()
|
||||
}.assert(0, afterPath, fileNamesData) {
|
||||
2(4.dot)
|
||||
4(6.dot)
|
||||
6()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun historyForDeleted() {
|
||||
val path = LocalFilePath("file.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(path)
|
||||
.addChange(path, 7, listOf(ADDED), listOf(7))
|
||||
.addChange(path, 4, listOf(MODIFIED), listOf(5))
|
||||
.addChange(path, 2, listOf(REMOVED), listOf(3))
|
||||
.build()
|
||||
|
||||
val graph = graph {
|
||||
0(1)
|
||||
1(2)
|
||||
2(3)
|
||||
3(4)
|
||||
4(5)
|
||||
5(6)
|
||||
6(7)
|
||||
7()
|
||||
}
|
||||
|
||||
graph.assert(0, path, fileNamesData) {
|
||||
2(4.dot)
|
||||
4(7.dot)
|
||||
7()
|
||||
}
|
||||
graph.assert(4, path, fileNamesData) {
|
||||
2(4.dot)
|
||||
4(7.dot)
|
||||
7()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun historyWithMerges() {
|
||||
val path = LocalFilePath("file.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(path)
|
||||
.addChange(path, 7, listOf(ADDED), listOf(7))
|
||||
.addChange(path, 6, listOf(MODIFIED), listOf(7))
|
||||
.addChange(path, 4, listOf(NOT_CHANGED, MODIFIED), listOf(6, 5))
|
||||
.addChange(path, 3, listOf(MODIFIED), listOf(6))
|
||||
.addChange(path, 2, listOf(MODIFIED), listOf(4))
|
||||
.addChange(path, 1, listOf(MODIFIED, MODIFIED), listOf(3, 2))
|
||||
.addChange(path, 0, listOf(MODIFIED), listOf(1))
|
||||
.build()
|
||||
|
||||
graph {
|
||||
0(1)
|
||||
1(2, 3)
|
||||
2(4)
|
||||
3(6)
|
||||
4(6, 5)
|
||||
5(7)
|
||||
6(7)
|
||||
7()
|
||||
}.assert(0, path, fileNamesData) {
|
||||
0(1)
|
||||
1(3, 2)
|
||||
2(6.dot)
|
||||
3(6)
|
||||
6(7)
|
||||
7()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename happens in one branch, while the other branch only consists of couple of trivial merge commits.
|
||||
* Refiner walks to the trivial branch first instead of meaningful branch and because of this misses the rename completely.
|
||||
* Solution would be to drop trivial merges before refining and always walk to the NOT_CHANGED branch.
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
fun historyWithUndetectedRename() {
|
||||
val after = LocalFilePath("after.txt", false)
|
||||
val before = LocalFilePath("before.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(after)
|
||||
.addChange(before, 7, listOf(ADDED), listOf(7))
|
||||
.addChange(before, 6, listOf(MODIFIED), listOf(7))
|
||||
.addChange(before, 5, listOf(MODIFIED), listOf(6))
|
||||
|
||||
.addChange(before, 4, listOf(REMOVED), listOf(5))
|
||||
.addChange(after, 4, listOf(ADDED), listOf(5))
|
||||
.addRename(5, 4, before, after)
|
||||
|
||||
.addChange(after, 3, listOf(MODIFIED), listOf(4))
|
||||
|
||||
.addChange(before, 2, listOf(MODIFIED, NOT_CHANGED), listOf(6, 5))
|
||||
.addChange(before, 1, listOf(REMOVED, NOT_CHANGED), listOf(2, 3))
|
||||
.addChange(after, 1, listOf(ADDED, NOT_CHANGED), listOf(2, 3))
|
||||
// rename is not detected at merge commit 1
|
||||
.addChange(after, 0, listOf(MODIFIED), listOf(1))
|
||||
.build()
|
||||
|
||||
graph {
|
||||
0(1)
|
||||
1(2, 3)
|
||||
2(6, 5)
|
||||
3(4)
|
||||
4(5)
|
||||
5(6)
|
||||
6(7)
|
||||
7()
|
||||
}.assert(0, after, fileNamesData) {
|
||||
0(3.dot)
|
||||
3(4)
|
||||
4(5)
|
||||
5(6)
|
||||
6(7)
|
||||
7()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cyclicHistoryTest() {
|
||||
val aFile = LocalFilePath("a.txt", false)
|
||||
val bFile = LocalFilePath("b.txt", false)
|
||||
val fileNamesData = FileNamesDataBuilder(aFile)
|
||||
.addChange(aFile, 4, listOf(ADDED), listOf(4))
|
||||
.addChange(aFile, 2, listOf(REMOVED), listOf(3))
|
||||
.addChange(bFile, 2, listOf(ADDED), listOf(3))
|
||||
.addRename(3, 2, aFile, bFile)
|
||||
.addChange(bFile, 0, listOf(REMOVED), listOf(1))
|
||||
.addChange(aFile, 0, listOf(ADDED), listOf(1))
|
||||
.addRename(1, 0, bFile, aFile)
|
||||
.build()
|
||||
|
||||
graph {
|
||||
0(1)
|
||||
1(2)
|
||||
2(3)
|
||||
3(4)
|
||||
4()
|
||||
}.assert(0, aFile, fileNamesData) {
|
||||
0(2.dot)
|
||||
2(4.dot)
|
||||
4()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FileNamesDataBuilder(private val path: FilePath) {
|
||||
private val commitsMap: MutableMap<FilePath, TIntObjectHashMap<TIntObjectHashMap<VcsLogPathsIndex.ChangeKind>>> = mutableMapOf()
|
||||
private val renamesMap: MutableMap<Couple<Int>, Couple<FilePath>> = mutableMapOf()
|
||||
|
||||
fun addRename(parent: Int, child: Int, beforePath: FilePath, afterPath: FilePath): FileNamesDataBuilder {
|
||||
renamesMap[Couple(parent, child)] = Couple(beforePath, afterPath)
|
||||
return this
|
||||
}
|
||||
|
||||
fun addChange(path: FilePath, commit: Int, changes: List<VcsLogPathsIndex.ChangeKind>, parents: List<Int>): FileNamesDataBuilder {
|
||||
commitsMap.getOrPut(path) { TIntObjectHashMap() }.put(commit, parents.zip(changes).toIntObjectMap())
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): FileNamesData {
|
||||
return object : FileNamesData(path) {
|
||||
override fun findRename(parent: Int, child: Int, accept: (Couple<FilePath>) -> Boolean): Couple<FilePath>? {
|
||||
return renamesMap[Couple(parent, child)]
|
||||
}
|
||||
|
||||
override fun getAffectedCommits(path: FilePath): TIntObjectHashMap<TIntObjectHashMap<VcsLogPathsIndex.ChangeKind>> {
|
||||
return commitsMap[path] ?: TIntObjectHashMap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> List<Pair<Int, T>>.toIntObjectMap(): TIntObjectHashMap<T> {
|
||||
val result = TIntObjectHashMap<T>()
|
||||
this.forEach { result.put(it.first, it.second) }
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user