Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2016-11-14 15:17:19 +01:00
18 changed files with 585 additions and 244 deletions
@@ -88,7 +88,8 @@ class InlayAssert(private val file: PsiFile, val inlays: List<Inlay>) {
val hintOffsets = hints.map { it.first }
val hintNames = hints.map { it.second }
assertThat(hints.size).isEqualTo(expectedInlays.size)
val elements = hintOffsets.mapNotNull { file.findElementAt(it) }
assertThat(hints.size).isEqualTo(expectedInlays.size).withFailMessage("Element at offsets: ${elements.joinToString(", ")}")
val expect = expectedInlays.map { it.substringBefore("->") to it.substringAfter("->") }
val expectedHintNames = expect.map { it.first }
@@ -96,8 +97,7 @@ class InlayAssert(private val file: PsiFile, val inlays: List<Inlay>) {
assertThat(hintNames).isEqualTo(expectedHintNames)
val wordsAfter = hintOffsets.mapNotNull { file.findElementAt(it) }.map { it.text }
val wordsAfter = elements.map { it.text }
assertThat(wordsAfter).isEqualTo(expectedWordsAfter)
}
@@ -708,13 +708,16 @@ class Key {
setup("""
class Test {
void test() {
xxx(100);
check(1 + 1);
int i=1; check(1 + 1 + 1);
}
void check(int isShow) {}
void xxx(int followTheSum) {}
}
""")
onLineStartingWith("xxx").assertInlays("followTheSum->100")
onLineStartingWith("check").assertInlays("isShow->1")
onLineStartingWith("int").assertInlays("isShow->1")
}
@@ -600,7 +600,8 @@ public class ByWord {
Range expanded = expandW(myText1, myText2, range);
Range trimmed = trim(myText1, myText2, expanded);
if (!trimmed.isEmpty()) {
if (!trimmed.isEmpty() &&
!isEqualsIW(myText1, myText2, trimmed)) {
myChanges.add(trimmed);
}
}
@@ -638,7 +639,8 @@ public class ByWord {
MergeRange expanded = expandW(myText1, myText2, myText3, range);
MergeRange trimmed = trim(myText1, myText2, myText3, expanded);
if (!trimmed.isEmpty()) {
if (!trimmed.isEmpty() &&
!isEqualsIW(myText1, myText2, myText3, trimmed)) {
myChanges.add(trimmed);
}
}
@@ -690,7 +692,8 @@ public class ByWord {
Range trimmed = new Range(start1, end1, start2, end2);
if (!trimmed.isEmpty()) {
if (!trimmed.isEmpty() &&
!isEquals(myText1, myText2, trimmed)) {
myChanges.add(trimmed);
}
}
@@ -753,7 +756,8 @@ public class ByWord {
MergeRange trimmed = new MergeRange(start1, end1, start2, end2, start3, end3);
if (!trimmed.isEmpty()) {
if (!trimmed.isEmpty() &&
!isEquals(myText1, myText2, myText3, trimmed)) {
myChanges.add(trimmed);
}
}
@@ -384,4 +384,40 @@ public class TrimUtil {
public static Range expandIW(@NotNull CharSequence text1, @NotNull CharSequence text2) {
return expandIW(text1, text2, 0, 0, text1.length(), text2.length());
}
//
// Equality
//
public static boolean isEquals(@NotNull CharSequence text1, @NotNull CharSequence text2,
@NotNull Range range) {
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
return ComparisonUtil.isEquals(sequence1, sequence2, ComparisonPolicy.DEFAULT);
}
public static boolean isEqualsIW(@NotNull CharSequence text1, @NotNull CharSequence text2,
@NotNull Range range) {
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
return ComparisonUtil.isEquals(sequence1, sequence2, ComparisonPolicy.IGNORE_WHITESPACES);
}
public static boolean isEquals(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull CharSequence text3,
@NotNull MergeRange range) {
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
CharSequence sequence3 = text3.subSequence(range.start3, range.end3);
return ComparisonUtil.isEquals(sequence2, sequence1, ComparisonPolicy.DEFAULT) &&
ComparisonUtil.isEquals(sequence2, sequence3, ComparisonPolicy.DEFAULT);
}
public static boolean isEqualsIW(@NotNull CharSequence text1, @NotNull CharSequence text2, @NotNull CharSequence text3,
@NotNull MergeRange range) {
CharSequence sequence1 = text1.subSequence(range.start1, range.end1);
CharSequence sequence2 = text2.subSequence(range.start2, range.end2);
CharSequence sequence3 = text3.subSequence(range.start3, range.end3);
return ComparisonUtil.isEquals(sequence2, sequence1, ComparisonPolicy.IGNORE_WHITESPACES) &&
ComparisonUtil.isEquals(sequence2, sequence3, ComparisonPolicy.IGNORE_WHITESPACES);
}
}
@@ -21,7 +21,6 @@ import com.intellij.diff.util.ThreeSide
import com.intellij.openapi.editor.Document
import com.intellij.openapi.progress.DumbProgressIndicator
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.util.Couple
import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
import com.intellij.testFramework.UsefulTestCase
@@ -66,6 +65,10 @@ abstract class DiffTestCase : UsefulTestCase() {
assertTrue(message, actual)
}
fun assertFalse(actual: Boolean, message: String = "") {
assertFalse(message, actual)
}
fun assertEquals(expected: Any?, actual: Any?, message: String = "") {
assertEquals(message, expected, actual)
}
@@ -75,17 +78,33 @@ abstract class DiffTestCase : UsefulTestCase() {
}
fun assertEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean, skipLastNewline: Boolean) {
if (skipLastNewline && !ignoreSpaces) {
assertTrue(StringUtil.equals(chunk1, chunk2) ||
StringUtil.equals(stripNewline(chunk1), chunk2) ||
StringUtil.equals(chunk1, stripNewline(chunk2)))
}
else {
assertTrue(isEqualsCharSequences(chunk1, chunk2, ignoreSpaces))
}
}
fun assertNotEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean, skipLastNewline: Boolean) {
if (skipLastNewline && !ignoreSpaces) {
assertTrue(!StringUtil.equals(chunk1, chunk2) ||
!StringUtil.equals(stripNewline(chunk1), chunk2) ||
!StringUtil.equals(chunk1, stripNewline(chunk2)))
}
else {
assertFalse(isEqualsCharSequences(chunk1, chunk2, ignoreSpaces))
}
}
fun isEqualsCharSequences(chunk1: CharSequence, chunk2: CharSequence, ignoreSpaces: Boolean): Boolean {
if (ignoreSpaces) {
assertTrue(StringUtil.equalsIgnoreWhitespaces(chunk1, chunk2))
} else {
if (skipLastNewline) {
if (StringUtil.equals(chunk1, chunk2)) return
if (StringUtil.equals(stripNewline(chunk1), chunk2)) return
if (StringUtil.equals(chunk1, stripNewline(chunk2))) return
assertTrue(false)
} else {
assertTrue(StringUtil.equals(chunk1, chunk2))
}
return StringUtil.equalsIgnoreWhitespaces(chunk1, chunk2)
}
else {
return StringUtil.equals(chunk1, chunk2)
}
}
@@ -202,14 +221,14 @@ abstract class DiffTestCase : UsefulTestCase() {
// Helpers
//
open class Trio<T : Any>(val data1: T, val data2: T, val data3: T) {
open class Trio<out T>(val data1: T, val data2: T, val data3: T) {
companion object {
fun <V : Any> from(f: (ThreeSide) -> V): Trio<V> = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT))
fun <V> from(f: (ThreeSide) -> V): Trio<V> = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT))
}
fun <V : Any> map(f: (T) -> V): Trio<V> = Trio(f(data1), f(data2), f(data3))
fun <V> map(f: (T) -> V): Trio<V> = Trio(f(data1), f(data2), f(data3))
fun <V : Any> map(f: (T, ThreeSide) -> V): Trio<V> = Trio(f(data1, ThreeSide.LEFT), f(data2, ThreeSide.BASE), f(data3, ThreeSide.RIGHT))
fun <V> map(f: (T, ThreeSide) -> V): Trio<V> = Trio(f(data1, ThreeSide.LEFT), f(data2, ThreeSide.BASE), f(data3, ThreeSide.RIGHT))
fun forEach(f: (T, ThreeSide) -> Unit): Unit {
f(data1, ThreeSide.LEFT)
@@ -228,7 +247,11 @@ abstract class DiffTestCase : UsefulTestCase() {
}
override fun hashCode(): Int {
return data1.hashCode() * 37 * 37 + data2.hashCode() * 37 + data3.hashCode()
var h = 0
if (data1 != null) h = h * 31 + data1.hashCode()
if (data2 != null) h = h * 31 + data2.hashCode()
if (data3 != null) h = h * 31 + data3.hashCode()
return h
}
}
}
@@ -26,28 +26,31 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.util.text.StringUtil
class ComparisonUtilAutoTest : DiffTestCase() {
val RUNS = 30
val MAX_LENGTH = 300
fun testChar() {
doTestChar(System.currentTimeMillis(), 30, 30)
doTestChar(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
fun testWord() {
doTestWord(System.currentTimeMillis(), 30, 300)
doTestWord(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
fun testLine() {
doTestLine(System.currentTimeMillis(), 30, 300)
doTestLine(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
fun testLineSquashed() {
doTestLineSquashed(System.currentTimeMillis(), 30, 300)
doTestLineSquashed(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
fun testLineTrimSquashed() {
doTestLineTrimSquashed(System.currentTimeMillis(), 30, 300)
doTestLineTrimSquashed(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
fun testMerge() {
doTestMerge(System.currentTimeMillis(), 30, 300)
doTestMerge(System.currentTimeMillis(), RUNS, MAX_LENGTH)
}
private fun doTestLine(seed: Long, runs: Int, maxLength: Int) {
@@ -141,8 +144,8 @@ class ComparisonUtilAutoTest : DiffTestCase() {
val chunk2 = DiffUtil.getLinesContent(text2, f.startLine2, f.endLine2)
val chunk3 = DiffUtil.getLinesContent(text3, f.startLine3, f.endLine3)
val wordFragments = ByWord.compare(chunk1, chunk2, chunk3, policy, INDICATOR);
MergeLineFragmentImpl(f, wordFragments);
val wordFragments = ByWord.compare(chunk1, chunk2, chunk3, policy, INDICATOR)
MergeLineFragmentImpl(f, wordFragments)
}
debugData.put("Fragments", fineFragments)
@@ -200,18 +203,18 @@ class ComparisonUtilAutoTest : DiffTestCase() {
}
}
checkUnchanged(text1.charsSequence, text2.charsSequence, fragments, policy, true)
checkValidRanges(text1.charsSequence, text2.charsSequence, fragments, policy, true)
checkCantTrimLines(text1, text2, fragments, policy, allowNonSquashed)
}
private fun checkResultWord(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy) {
checkDiffConsistency(fragments)
checkUnchanged(text1, text2, fragments, policy, false)
checkValidRanges(text1, text2, fragments, policy, false)
}
private fun checkResultChar(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy) {
checkDiffConsistency(fragments)
checkUnchanged(text1, text2, fragments, policy, false)
checkValidRanges(text1, text2, fragments, policy, false)
}
private fun checkResultMerge(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
@@ -223,10 +226,10 @@ class ComparisonUtilAutoTest : DiffTestCase() {
val chunk3 = DiffUtil.getLinesContent(text3, f.startLine3, f.endLine3)
checkDiffConsistency3(f.innerFragments!!)
checkUnchanged3(chunk1, chunk2, chunk3, f.innerFragments!!, policy)
checkValidRanges3(chunk1, chunk2, chunk3, f.innerFragments!!, policy)
}
checkUnchanged3(text1, text2, text3, fragments, policy)
checkValidRanges3(text1, text2, text3, fragments, policy)
checkCantTrimLines3(text1, text2, text3, fragments, policy)
}
@@ -374,28 +377,39 @@ class ComparisonUtilAutoTest : DiffTestCase() {
}
}
private fun checkUnchanged(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy, skipNewline: Boolean) {
private fun checkValidRanges(text1: CharSequence, text2: CharSequence, fragments: List<DiffFragment>, policy: ComparisonPolicy, skipNewline: Boolean) {
// TODO: better check for Trim spaces case ?
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
val ignoreSpacesUnchanged = policy != ComparisonPolicy.DEFAULT
val ignoreSpacesChanged = policy == ComparisonPolicy.IGNORE_WHITESPACES
var last1 = 0
var last2 = 0
for (fragment in fragments) {
val chunk1 = text1.subSequence(last1, fragment.startOffset1)
val chunk2 = text2.subSequence(last2, fragment.startOffset2)
val start1 = fragment.startOffset1
val start2 = fragment.startOffset2
val end1 = fragment.endOffset1
val end2 = fragment.endOffset2
assertEqualsCharSequences(chunk1, chunk2, ignoreSpaces, skipNewline)
val chunk1 = text1.subSequence(last1, start1)
val chunk2 = text2.subSequence(last2, start2)
assertEqualsCharSequences(chunk1, chunk2, ignoreSpacesUnchanged, skipNewline)
val chunkContent1 = text1.subSequence(start1, end1)
val chunkContent2 = text2.subSequence(start2, end2)
if (!skipNewline) {
assertNotEqualsCharSequences(chunkContent1, chunkContent2, ignoreSpacesChanged, skipNewline)
}
last1 = fragment.endOffset1
last2 = fragment.endOffset2
}
val chunk1 = text1.subSequence(last1, text1.length)
val chunk2 = text2.subSequence(last2, text2.length)
assertEqualsCharSequences(chunk1, chunk2, ignoreSpaces, skipNewline)
assertEqualsCharSequences(chunk1, chunk2, ignoreSpacesUnchanged, skipNewline)
}
private fun checkUnchanged3(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
private fun checkValidRanges3(text1: Document, text2: Document, text3: Document, fragments: List<MergeLineFragment>, policy: ComparisonPolicy) {
val ignoreSpaces = policy != ComparisonPolicy.DEFAULT
var last1 = 0
var last2 = 0
@@ -425,8 +439,9 @@ class ComparisonUtilAutoTest : DiffTestCase() {
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
}
private fun checkUnchanged3(text1: CharSequence, text2: CharSequence, text3: CharSequence, fragments: List<MergeWordFragment>, policy: ComparisonPolicy) {
val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT
private fun checkValidRanges3(text1: CharSequence, text2: CharSequence, text3: CharSequence, fragments: List<MergeWordFragment>, policy: ComparisonPolicy) {
val ignoreSpacesUnchanged = policy != ComparisonPolicy.DEFAULT
val ignoreSpacesChanged = policy == ComparisonPolicy.IGNORE_WHITESPACES
var last1 = 0
var last2 = 0
@@ -435,13 +450,21 @@ class ComparisonUtilAutoTest : DiffTestCase() {
val start1 = fragment.startOffset1
val start2 = fragment.startOffset2
val start3 = fragment.startOffset3
val end1 = fragment.endOffset1
val end2 = fragment.endOffset2
val end3 = fragment.endOffset3
val content1 = text1.subSequence(last1, start1)
val content2 = text2.subSequence(last2, start2)
val content3 = text3.subSequence(last3, start3)
assertEqualsCharSequences(content2, content1, ignoreSpacesUnchanged, false)
assertEqualsCharSequences(content2, content3, ignoreSpacesUnchanged, false)
assertEqualsCharSequences(content2, content1, ignoreSpaces, false)
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
val chunkContent1 = text1.subSequence(start1, end1)
val chunkContent2 = text2.subSequence(start2, end2)
val chunkContent3 = text3.subSequence(start3, end3)
assertFalse(isEqualsCharSequences(chunkContent2, chunkContent1, ignoreSpacesChanged) &&
isEqualsCharSequences(chunkContent2, chunkContent3, ignoreSpacesChanged))
last1 = fragment.endOffset1
last2 = fragment.endOffset2
@@ -452,8 +475,8 @@ class ComparisonUtilAutoTest : DiffTestCase() {
val content2 = text2.subSequence(last2, text2.length)
val content3 = text3.subSequence(last3, text3.length)
assertEqualsCharSequences(content2, content1, ignoreSpaces, false)
assertEqualsCharSequences(content2, content3, ignoreSpaces, false)
assertEqualsCharSequences(content2, content1, ignoreSpacesUnchanged, false)
assertEqualsCharSequences(content2, content3, ignoreSpacesUnchanged, false)
}
private fun checkCantTrimLines(text1: Document, text2: Document, fragments: List<LineFragment>, policy: ComparisonPolicy, allowNonSquashed: Boolean) {
@@ -491,11 +514,7 @@ class ComparisonUtilAutoTest : DiffTestCase() {
}
private fun countNonWhitespaceCharacters(line: CharSequence): Int {
var count = 0
for (i in 0 until line.length) {
if (!StringUtil.isWhiteSpace(line[i])) count++
}
return count
return (0 until line.length).count { !StringUtil.isWhiteSpace(line[it]) }
}
private fun getFirstLastLines(text: Document, start: Int, end: Int): Couple<CharSequence>? {
@@ -18,6 +18,9 @@ package com.intellij.diff.comparison
import com.intellij.diff.DiffTestCase
import com.intellij.diff.fragments.DiffFragment
import com.intellij.diff.fragments.LineFragment
import com.intellij.diff.fragments.MergeWordFragment
import com.intellij.diff.util.IntPair
import com.intellij.diff.util.ThreeSide
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.impl.DocumentImpl
import com.intellij.openapi.util.Couple
@@ -25,31 +28,64 @@ import com.intellij.util.containers.ContainerUtil
import java.util.*
abstract class ComparisonUtilTestBase : DiffTestCase() {
private fun doLineTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
private fun doLineTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
val before = text.first
val after = text.second
val fragments = MANAGER.compareLines(before.charsSequence, after.charsSequence, policy, INDICATOR)
checkConsistency(fragments, before, after)
if (matchings != null) checkLineMatching(fragments, matchings)
if (expected != null) checkLineChanges(fragments, expected)
}
private fun doWordTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
private fun doLineInnerTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
val before = text.first
val after = text.second
val rawFragments = MANAGER.compareLinesInner(before.charsSequence, after.charsSequence, policy, INDICATOR)
val fragments = MANAGER.squash(rawFragments)
checkConsistencyWord(fragments, before, after)
checkConsistencyLineInner(fragments, before, after)
val diffFragments = fragments[0].innerFragments!!
if (matchings != null) checkDiffMatching(diffFragments, matchings)
if (expected != null) checkDiffChanges(diffFragments, expected)
}
private fun doCharTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
private fun doWordTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
val before = text.first
val after = text.second
val fragments = MANAGER.compareWords(before.charsSequence, after.charsSequence, policy, INDICATOR)
checkConsistency(fragments, before, after)
if (matchings != null) checkDiffMatching(fragments, matchings)
if (expected != null) checkDiffChanges(fragments, expected)
}
private fun doWordTest(text: Trio<Document>, matchings: Trio<BitSet>?, expected: List<Trio<IntPair>>?, policy: ComparisonPolicy) {
val before = text.data1
val base = text.data2
val after = text.data3
val fragments = ByWord.compare(before.charsSequence, base.charsSequence, after.charsSequence, policy, INDICATOR)
checkConsistency(fragments)
if (matchings != null) checkMergeMatching(fragments, matchings)
if (expected != null) checkMergeChanges(fragments, expected)
}
private fun doCharTest(text: Couple<Document>, matchings: Couple<BitSet>?, expected: List<Couple<IntPair>>?, policy: ComparisonPolicy) {
val before = text.first
val after = text.second
val fragments = MANAGER.compareChars(before.charsSequence, after.charsSequence, policy, INDICATOR)
checkConsistency(fragments, before, after)
if (matchings != null) checkDiffMatching(fragments, matchings)
if (expected != null) checkDiffChanges(fragments, expected)
}
private fun doSplitterTest(before: Document, after: Document, squash: Boolean, trim: Boolean, expected: List<Change>?, policy: ComparisonPolicy) {
private fun doSplitterTest(text: Couple<Document>,
squash: Boolean,
trim: Boolean,
expected: List<Couple<IntPair>>?,
policy: ComparisonPolicy) {
val before = text.first
val after = text.second
val text1 = before.charsSequence
val text2 = after.charsSequence
@@ -62,7 +98,7 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
if (expected != null) checkLineChanges(fragments, expected)
}
private fun checkConsistencyWord(fragments: List<LineFragment>, before: Document, after: Document) {
private fun checkConsistencyLineInner(fragments: List<LineFragment>, before: Document, after: Document) {
assertTrue(fragments.size == 1)
val fragment = fragments[0]
@@ -102,16 +138,33 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
}
}
private fun checkLineChanges(fragments: List<LineFragment>, expected: List<Change>) {
private fun checkConsistency(fragments: List<MergeWordFragment>) {
for (fragment in fragments) {
assertTrue(fragment.getStartOffset(ThreeSide.LEFT) <= fragment.getEndOffset(ThreeSide.LEFT))
assertTrue(fragment.getStartOffset(ThreeSide.BASE) <= fragment.getEndOffset(ThreeSide.BASE))
assertTrue(fragment.getStartOffset(ThreeSide.RIGHT) <= fragment.getEndOffset(ThreeSide.RIGHT))
assertTrue(fragment.getStartOffset(ThreeSide.LEFT) != fragment.getEndOffset(ThreeSide.LEFT) ||
fragment.getStartOffset(ThreeSide.BASE) != fragment.getEndOffset(ThreeSide.BASE) ||
fragment.getStartOffset(ThreeSide.RIGHT) != fragment.getEndOffset(ThreeSide.RIGHT))
}
}
private fun checkLineChanges(fragments: List<LineFragment>, expected: List<Couple<IntPair>>) {
val changes = convertLineFragments(fragments)
assertOrderedEquals(changes, expected)
}
private fun checkDiffChanges(fragments: List<DiffFragment>, expected: List<Change>) {
private fun checkDiffChanges(fragments: List<DiffFragment>, expected: List<Couple<IntPair>>) {
val changes = convertDiffFragments(fragments)
assertOrderedEquals(changes, expected)
}
private fun checkMergeChanges(fragments: List<MergeWordFragment>, expected: List<Trio<IntPair>>) {
val changes = convertMergeFragments(fragments)
assertOrderedEquals(changes, expected)
}
private fun checkLineMatching(fragments: List<LineFragment>, matchings: Couple<BitSet>) {
val set1 = BitSet()
val set2 = BitSet()
@@ -120,8 +173,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
set2.set(fragment.startLine2, fragment.endLine2)
}
assertEquals(matchings.first, set1)
assertEquals(matchings.second, set2)
assertEquals(matchings.first, set1, "Before")
assertEquals(matchings.second, set2, "After")
}
private fun checkDiffMatching(fragments: List<DiffFragment>, matchings: Couple<BitSet>) {
@@ -132,16 +185,39 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
set2.set(fragment.startOffset2, fragment.endOffset2)
}
assertEquals(matchings.first, set1)
assertEquals(matchings.second, set2)
assertEquals(matchings.first, set1, "Before")
assertEquals(matchings.second, set2, "After")
}
private fun convertDiffFragments(fragments: List<DiffFragment>): List<Change> {
return fragments.map { Change(it.startOffset1, it.endOffset1, it.startOffset2, it.endOffset2) }
private fun checkMergeMatching(fragments: List<MergeWordFragment>, matchings: Trio<BitSet>) {
val set1 = BitSet()
val set2 = BitSet()
val set3 = BitSet()
for (fragment in fragments) {
set1.set(fragment.getStartOffset(ThreeSide.LEFT), fragment.getEndOffset(ThreeSide.LEFT))
set2.set(fragment.getStartOffset(ThreeSide.BASE), fragment.getEndOffset(ThreeSide.BASE))
set3.set(fragment.getStartOffset(ThreeSide.RIGHT), fragment.getEndOffset(ThreeSide.RIGHT))
}
assertEquals(matchings.data1, set1, "Before")
assertEquals(matchings.data2, set2, "Base")
assertEquals(matchings.data3, set3, "After")
}
private fun convertLineFragments(fragments: List<LineFragment>): List<Change> {
return fragments.map { Change(it.startLine1, it.endLine1, it.startLine2, it.endLine2) }
private fun convertDiffFragments(fragments: List<DiffFragment>): List<Couple<IntPair>> {
return fragments.map { Couple(IntPair(it.startOffset1, it.endOffset1), IntPair(it.startOffset2, it.endOffset2)) }
}
private fun convertLineFragments(fragments: List<LineFragment>): List<Couple<IntPair>> {
return fragments.map { Couple(IntPair(it.startLine1, it.endLine1), IntPair(it.startLine2, it.endLine2)) }
}
private fun convertMergeFragments(fragments: List<MergeWordFragment>): List<Trio<IntPair>> {
return fragments.map {
Trio(IntPair(it.getStartOffset(ThreeSide.LEFT), it.getEndOffset(ThreeSide.LEFT)),
IntPair(it.getStartOffset(ThreeSide.BASE), it.getEndOffset(ThreeSide.BASE)),
IntPair(it.getStartOffset(ThreeSide.RIGHT), it.getEndOffset(ThreeSide.RIGHT)))
}
}
private fun checkLineOffsets(fragment: LineFragment, before: Document, after: Document) {
@@ -168,39 +244,51 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
// Test Builder
//
private fun parseLineMatching(matching: String, document: Document): BitSet {
assertEquals(matching.length, document.textLength)
val lines1 = matching.split('_', '*')
val lines2 = document.charsSequence.split('\n')
assertEquals(lines1.size, lines2.size)
for (i in 0..lines1.size - 1) {
assertEquals(lines1[i].length, lines2[i].length, "line $i")
}
val set = BitSet()
var index = 0
var lineNumber = 0
while (index < matching.length) {
var end = matching.indexOfAny(listOf("_", "*"), index) + 1
if (end == 0) end = matching.length
val line = matching.subSequence(index, end)
if (line.find { it != ' ' && it != '_' } != null) {
assert(!line.contains(' '))
set.set(lineNumber)
}
lineNumber++
index = end
}
return set
}
internal enum class TestType {
LINE, WORD, CHAR, SPLITTER
LINE, LINE_INNER, WORD, CHAR, SPLITTER
}
internal inner class TestBuilder(private val type: TestType) {
private var isExecuted: Boolean = false
private var before: Document? = null
private var after: Document? = null
private var defaultChanges: List<Change>? = null
private var trimChanges: List<Change>? = null
private var ignoreChanges: List<Change>? = null
private var defaultMatching: Couple<BitSet>? = null
private var trimMatching: Couple<BitSet>? = null
private var ignoreMatching: Couple<BitSet>? = null
private var text: Data<Document> = Data()
private var changes: PolicyData<List<Data<IntPair>>> = PolicyData()
private var matchings: PolicyData<Data<BitSet>> = PolicyData()
private var shouldSquash: Boolean = false
private var shouldTrim: Boolean = false
private fun changes(policy: ComparisonPolicy): List<Change>? = when (policy) {
ComparisonPolicy.IGNORE_WHITESPACES -> ignoreChanges ?: trimChanges ?: defaultChanges
ComparisonPolicy.TRIM_WHITESPACES -> trimChanges ?: defaultChanges
ComparisonPolicy.DEFAULT -> defaultChanges
}
private fun matchings(policy: ComparisonPolicy): Couple<BitSet>? = when (policy) {
ComparisonPolicy.IGNORE_WHITESPACES -> ignoreMatching ?: trimMatching ?: defaultMatching
ComparisonPolicy.TRIM_WHITESPACES -> trimMatching ?: defaultMatching
ComparisonPolicy.DEFAULT -> defaultMatching
}
fun assertExecuted() {
assertTrue(isExecuted)
}
@@ -209,17 +297,36 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
try {
isExecuted = true
val change = changes(policy)
val matchings = matchings(policy)
assertTrue(change != null || matchings != null)
if (text.isTwoSide()) {
val text = text.asCouple()
val changes = changes.get(policy)?.map { it.asCouple() }
val matchings = matchings.get(policy)?.asCouple()
assertTrue(changes != null || matchings != null)
when (type) {
TestType.LINE -> doLineTest(before!!, after!!, matchings, change, policy)
TestType.WORD -> doWordTest(before!!, after!!, matchings, change, policy)
TestType.CHAR -> doCharTest(before!!, after!!, matchings, change, policy)
TestType.SPLITTER -> {
assertNull(matchings)
doSplitterTest(before!!, after!!, shouldSquash, shouldTrim, change, policy)
when (type) {
TestType.LINE -> doLineTest(text, matchings, changes, policy)
TestType.LINE_INNER -> {
doLineInnerTest(text, matchings, changes, policy)
doWordTest(text, matchings, changes, policy)
}
TestType.WORD -> doWordTest(text, matchings, changes, policy)
TestType.CHAR -> doCharTest(text, matchings, changes, policy)
TestType.SPLITTER -> {
assertNull(matchings)
doSplitterTest(text, shouldSquash, shouldTrim, changes, policy)
}
else -> assert(false)
}
}
else {
val text = text.asTrio()
val changes = changes.get(policy)?.map { it.asTrio() }
val matchings = matchings.get(policy)?.asTrio()
assertTrue(changes != null || matchings != null)
when (type) {
TestType.WORD -> doWordTest(text, matchings, changes, policy)
else -> assert(false)
}
}
}
@@ -254,102 +361,84 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
return Helper(this, v)
}
inner class Helper(val before: String, val after: String) {
operator fun Helper.minus(v: String): Helper {
return Helper(before, v, after)
}
inner class Helper(val before: String, val after: String, val base: String? = null) {
init {
val builder = this@TestBuilder
if (builder.before == null && builder.after == null) {
builder.before = DocumentImpl(parseSource(before))
builder.after = DocumentImpl(parseSource(after))
if (builder.text.before == null && builder.text.after == null ||
base != null && builder.text.base == null) {
builder.text.before = DocumentImpl(parseSource(before))
builder.text.after = DocumentImpl(parseSource(after))
if (base != null) builder.text.base = DocumentImpl(parseSource(base))
}
}
fun plainSource() {
val builder = this@TestBuilder
builder.before = DocumentImpl(before)
builder.after = DocumentImpl(after)
builder.text.before = DocumentImpl(before)
builder.text.after = DocumentImpl(after)
if (base != null) {
builder.text.base = DocumentImpl(base)
}
}
fun default() {
defaultMatching = parseMatching(before, after)
matchings.default = parseMatching(before, after, base)
}
fun trim() {
trimMatching = parseMatching(before, after)
matchings.trim = parseMatching(before, after, base)
}
fun ignore() {
ignoreMatching = parseMatching(before, after)
matchings.ignore = parseMatching(before, after, base)
}
private fun parseMatching(before: String, after: String): Couple<BitSet> {
private fun parseMatching(before: String, after: String, base: String?): Data<BitSet> {
if (type == TestType.LINE) {
val builder = this@TestBuilder
return Couple.of(parseLineMatching(before, builder.before!!), parseLineMatching(after, builder.after!!))
return Data(parseLineMatching(before, builder.text.before!!),
if (base != null) parseLineMatching(base, builder.text.base!!) else null,
parseLineMatching(after, builder.text.after!!))
}
else {
return Couple.of(parseMatching(before), parseMatching(after))
return Data(parseMatching(before),
if (base != null) parseMatching(base) else null,
parseMatching(after))
}
}
fun parseLineMatching(matching: String, document: Document): BitSet {
assertEquals(matching.length, document.textLength)
val lines1 = matching.split('_', '*')
val lines2 = document.charsSequence.split('\n')
assertEquals(lines1.size, lines2.size)
for (i in 0..lines1.size - 1) {
assertEquals(lines1[i].length, lines2[i].length, "line $i")
}
val set = BitSet()
var index = 0
var lineNumber = 0
while (index < matching.length) {
var end = matching.indexOfAny(listOf("_", "*"), index) + 1
if (end == 0) end = matching.length
val line = matching.subSequence(index, end)
if (line.find { it != ' ' && it != '_' } != null) {
assert(!line.contains(' '))
set.set(lineNumber)
}
lineNumber++
index = end
}
return set
}
}
fun default(vararg expected: Change): Unit {
defaultChanges = ContainerUtil.list(*expected)
fun default(vararg expected: Couple<IntPair>): Unit {
changes.default = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
}
fun trim(vararg expected: Change): Unit {
trimChanges = ContainerUtil.list(*expected)
fun trim(vararg expected: Couple<IntPair>): Unit {
changes.trim = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
}
fun ignore(vararg expected: Change): Unit {
ignoreChanges = ContainerUtil.list(*expected)
fun ignore(vararg expected: Couple<IntPair>): Unit {
changes.ignore = ContainerUtil.list(*expected).map { Data(it.first, it.second) }
}
fun mod(line1: Int, line2: Int, count1: Int, count2: Int): Change {
fun mod(line1: Int, line2: Int, count1: Int, count2: Int): Couple<IntPair> {
assert(count1 != 0)
assert(count2 != 0)
return Change(line1, line1 + count1, line2, line2 + count2)
return Couple(IntPair(line1, line1 + count1), IntPair(line2, line2 + count2))
}
fun del(line1: Int, line2: Int, count1: Int): Change {
fun del(line1: Int, line2: Int, count1: Int): Couple<IntPair> {
assert(count1 != 0)
return Change(line1, line1 + count1, line2, line2)
return Couple(IntPair(line1, line1 + count1), IntPair(line2, line2))
}
fun ins(line1: Int, line2: Int, count2: Int): Change {
fun ins(line1: Int, line2: Int, count2: Int): Couple<IntPair> {
assert(count2 != 0)
return Change(line1, line1, line2, line2 + count2)
return Couple(IntPair(line1, line1), IntPair(line2, line2 + count2))
}
@@ -361,6 +450,8 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
internal fun lines(f: TestBuilder.() -> Unit): Unit = doTest(TestType.LINE, f)
internal fun lines_inner(f: TestBuilder.() -> Unit): Unit = doTest(TestType.LINE_INNER, f)
internal fun words(f: TestBuilder.() -> Unit): Unit = doTest(TestType.WORD, f)
internal fun chars(f: TestBuilder.() -> Unit): Unit = doTest(TestType.CHAR, f)
@@ -382,9 +473,28 @@ abstract class ComparisonUtilTestBase : DiffTestCase() {
// Helpers
//
data class Change(val start1: Int, val end1: Int, val start2: Int, val end2: Int) {
override fun toString(): String {
return "($start1, $end1) - ($start2, $end2)"
private data class Data<T>(var before: T?, var base: T?, var after: T?) {
constructor() : this(null, null, null)
constructor(before: T?, after : T?) : this(before, null, after)
fun isTwoSide(): Boolean = before != null && after != null && base == null
fun isThreeSide(): Boolean = before != null && after != null && base != null
fun asCouple(): Couple<T> {
assert(isTwoSide())
return Couple(before!!, after!!)
}
fun asTrio(): Trio<T> {
assert(isThreeSide())
return Trio(before!!, base!!, after!!)
}
}
private data class PolicyData<T>(var default: T? = null, var trim: T? = null, var ignore: T? = null) {
fun get(policy: ComparisonPolicy): T? =
when (policy) {
ComparisonPolicy.IGNORE_WHITESPACES -> ignore ?: trim ?: default
ComparisonPolicy.TRIM_WHITESPACES -> trim ?: default
ComparisonPolicy.DEFAULT -> default
}
}
}
@@ -187,25 +187,31 @@ class MergeResolveUtilTest : DiffTestCase() {
)
}
fun testRegressions() {
test(
"i\n",
"i",
"\ni",
"i\n",
"i"
)
}
private fun testGreedy(base: String, left: String, right: String, expected: String?) {
test(base, left, right, expected, true);
test(base, left, right, expected, true)
}
private fun test(base: String, left: String, right: String, expected: String?, isGreedy: Boolean = false) {
val simpleResult = MergeResolveUtil.tryResolve(left, base, right)
val magicResult = MergeResolveUtil.tryGreedyResolve(left, base, right);
val expectedSimple = if (isGreedy) null else expected
val expectedGreedy = expected
test(base, left, right, expectedSimple, expectedGreedy)
}
if (expected == null) {
assertNull(simpleResult)
assertNull(magicResult)
}
else if (isGreedy) {
assertNull(simpleResult)
assertEquals(expected, magicResult)
}
else {
assertEquals(expected, simpleResult)
assertEquals(expected, magicResult)
}
private fun test(base: String, left: String, right: String, expectedSimple: String?, expectedGreedy: String?) {
val simpleResult = MergeResolveUtil.tryResolve(left, base, right)
val greedyResult = MergeResolveUtil.tryGreedyResolve(left, base, right)
assertEquals(expectedSimple, simpleResult, "Simple")
assertEquals(expectedGreedy, greedyResult, "Greedy")
}
}
@@ -17,72 +17,72 @@ package com.intellij.diff.comparison
class WordComparisonUtilTest : ComparisonUtilTestBase() {
fun testSimpleCases() {
words {
lines_inner {
("x z" - "y z")
("- " - "- ").default()
testAll()
}
words {
lines_inner {
("x z" - "y z")
("- " - "- ").default()
testAll()
}
words {
lines_inner {
(" x z" - "y z")
("-- " - "- ").default()
(" - " - "- ").trim()
testAll()
}
words {
lines_inner {
("x z " - "y z")
("- -" - "- ").default()
("- " - "- ").trim()
testAll()
}
words {
lines_inner {
("x z " - "y z")
("- -" - "- ").default()
("- " - "- ").trim()
testAll()
}
words {
lines_inner {
("x z" - " y z ")
("- " - "-- -").default()
("- " - " - ").trim()
testAll()
}
words {
lines_inner {
("x y" - "x z ")
(" -" - " --").default()
(" -" - " - ").trim()
testAll()
}
words {
lines_inner {
("x,y" - "x")
(" --" - " ").default()
testAll()
}
words {
lines_inner {
("x,y" - "y")
("-- " - " ").default()
testAll()
}
words {
lines_inner {
(".x=" - ".!=")
(" - " - " - ").default()
testAll()
}
words {
lines_inner {
("X xyz1 Z" - "X xyz2 Z")
(" ---- " - " ---- ").default()
testAll()
@@ -90,52 +90,52 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testPunctuation() {
words {
lines_inner {
(" x.z.x " - "x..x")
("- - -" - " ").default()
(" - " - " ").trim()
testAll()
}
words {
lines_inner {
("x..x" - " x.z.x ")
(" " - "- - -").default()
(" " - " - ").trim()
testAll()
}
words {
lines_inner {
("x ... z" - "y ... z")
("- " - "- ").default()
testAll()
}
words {
lines_inner {
("x ... z" - "x ... y")
(" -" - " -").default()
testAll()
}
words {
lines_inner {
("x ,... z" - "x ... y")
(" - -" - " -").default()
testAll()
}
words {
lines_inner {
("x . , .. z" - "x ... y")
(" --- -" - " -").default()
(" - -" - " -").ignore()
testAll()
}
words {
lines_inner {
("x==y==z" - "x====z")
(" - " - " ").default()
testAll()
}
words {
lines_inner {
("x====z" - "x==t==z")
(" " - " - ").default()
testAll()
@@ -143,13 +143,13 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testOldDiffBug() {
words {
lines_inner {
("x'y'>" - "x'>")
(" -- " - " ").default()
testAll()
}
words {
lines_inner {
("x'>" - "x'y'>")
(" " - " -- ").default()
testAll()
@@ -157,14 +157,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testWhitespaceOnlyChanges() {
words {
lines_inner {
("x =z" - "x= z")
(" -- " - " -- ").default()
testDefault()
testTrim()
}
words {
lines_inner {
("x =" - "x= z")
(" -- " - " ---").default()
(" " - " -").ignore()
@@ -173,7 +173,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testNewlines() {
words {
lines_inner {
(" x _ y _ z " - "x z")
("- ------ -" - " ").default()
(" - " - " ").trim()
@@ -181,17 +181,48 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words {
lines_inner {
("x z" - " x _ y _ z ")
(" " - "- ------ -").default()
(" " - " - ").trim()
(" " - " - ").ignore()
testAll()
}
words {
("_i" - "i_")
("- " - " -").default()
(" " - " ").trim()
testAll()
}
words {
("i_" - "_i")
("- " - " -").default() // TODO
testAll()
}
words {
("x_y" - "xy")
(" " - " ").ignore()
testIgnore()
}
words {
("A x_y B" - "a xy b")
("-------" - "------").ignore()
testIgnore()
}
words {
("A xy B" - "a xy b")
("- -" - "- -").ignore()
testIgnore()
}
}
fun testFixedBugs() {
words {
lines_inner {
(".! " - ". y!")
(" -" - " --- ").default()
(" " - " --- ").trim()
@@ -199,7 +230,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words {
lines_inner {
(" x n" - " y_ x m")
(" -" - "---- -").default()
(" -" - " - -").trim()
@@ -207,7 +238,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words {
lines_inner {
("x_" - "x! ")
(" -" - " ---").default()
(" " - " - ").trim()
@@ -217,35 +248,35 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testInnerWhitespaces() {
words {
lines_inner {
("<< x >>" - "<.<>.>")
(" --- " - " - - ").default()
(" - " - " - - ").ignore()
testAll()
}
words {
lines_inner {
("<< x >>" - "y<<x>>y")
(" - - " - "- -").default()
(" " - "- -").ignore()
testAll()
}
words {
lines_inner {
("x .. z" - "x y .. z")
(" " - " -- ").default() // TODO: looks wrong
(" " - " -- ").default()
(" " - " - ").ignore()
testAll()
}
words {
lines_inner {
(" x..z" - "x..y ")
("-- -" - " ---").default()
(" -" - " - ").trim()
testAll()
}
words {
lines_inner {
(" x y x _ x z x " - "x x_x x")
("- -- - - -- -" - " ").default()
(" -- -- " - " ").trim()
@@ -256,28 +287,28 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
fun testAlgorithmSpecific() {
// prefer words over punctuation
words {
lines_inner {
("...x" - "x...")
("--- " - " ---").default()
testAll()
}
// prefer longer words sequences
words {
lines_inner {
("x x y" - "x y")
("-- " - " ").default()
("- " - " ").ignore()
testAll()
}
words {
lines_inner {
("y x x" - "y x")
(" --" - " ").default()
(" -" - " ").ignore()
testAll()
}
words {
lines_inner {
("A X A B" - "A B")
("---- " - " ").default()
("--- " - " ").ignore()
@@ -285,14 +316,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
// prefer less modified 'sentences'
words {
lines_inner {
("A.X A.Z" - "A.X A.Y A.Z")
(" " - " ---- ").default()
(" " - " --- ").ignore()
testAll()
}
words {
lines_inner {
("X.A Z.A" - "X.A Y.A Z.A")
(" " - " ---- ").default()
(" " - " --- ").ignore()
@@ -300,7 +331,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
// prefer punctuation over whitespaces
words {
lines_inner {
(". " - " .")
(" ---" - "--- ").default()
testDefault()
@@ -308,26 +339,26 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun `test legacy cases from ByWordTest`() {
words {
lines_inner {
("abc def, 123" - "ab def, 12")
("--- ---" - "-- --").default()
testAll()
}
words {
lines_inner {
(" a[xy]+1" - ",a[]+1")
("- -- " - "- ").default()
(" -- " - "- ").trim()
testAll()
}
words {
lines_inner {
("0987_ a.g();_" - "yyyy_")
("------------- " - "---- ").default()
testAll()
}
words {
lines_inner {
(" abc_2222_" - " x = abc_zzzz_")
//(" ---- " - "-- ---- ---- ").legacy()
(" ---- " - " ------ ---- ").default()
@@ -335,7 +366,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words { // Idea58505
lines_inner { // Idea58505
(" if (eventMerger!=null && !dataSelection.getValueIsAdjusting()) {" -
" if (eventMerger!=null && (dataSelection==null || !dataSelection.getValueIsAdjusting())) {")
//(" - " -
@@ -347,7 +378,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words { // Idea56428
lines_inner { // Idea56428
("messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?)\");" -
"messageInsertStatement = connection.prepareStatement(\"INSERT INTO AUDIT (AUDIT_TYPE_ID, CREATION_TIMESTAMP, STATUS, SERVER_ID, INSTANCE_ID, REQUEST_ID) VALUES (?, ?, ?, ?, ?, ?)\");").plainSource()
//(" . . " -
@@ -359,14 +390,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words {
lines_inner {
("f(a, b);" - "f(a,_ b);")
(" " - " -- ").default()
(" " - " ").trim()
testAll()
}
words {
lines_inner {
(" o.f(a)" - "o. f( b)")
("- - " - " - -- ").default()
(" - " - " - -- ").trim()
@@ -374,7 +405,7 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
testAll()
}
words {
lines_inner {
(" 123 " - "xyz")
(" --- " - "---").trim()
testTrim()
@@ -382,14 +413,14 @@ class WordComparisonUtilTest : ComparisonUtilTestBase() {
}
fun testEmptyRangePositions() {
words {
lines_inner {
("x? y" - "x y")
(" - " - " ").default()
default(del(1, 1, 1))
testAll()
}
words {
lines_inner {
("x ?y" - "x y")
(" - " - " ").default()
default(del(2, 2, 1))
@@ -0,0 +1,108 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.diff.comparison
class WordMergeComparisonUtilTest : ComparisonUtilTestBase() {
fun testSimple() {
words {
("" - "" - "")
("" - "" - "").default()
testAll()
}
words {
("" - "X" - "")
("" - "-" - "").default()
testAll()
}
words {
("X" - "" - "")
("-" - "" - "").default()
testAll()
}
words {
("a b" - "a b" - "a b")
(" " - " " - " ").default()
testAll()
}
words {
("A b c" - "a b c" - "a b C")
("- -" - "- -" - "- -").default()
testAll()
}
words {
("a c" - "a c" - "a X c")
(" " - " " - " -- ").default()
(" " - " " - " - ").ignore()
testAll()
}
words {
("a X c" - "a X c" - "a c")
(" -- " - " -- " - " ").default()
(" - " - " - " - " ").ignore()
testAll()
}
words {
("a X c" - "a c" - "a Y c")
(" -- " - " " - " -- ").default()
(" - " - " " - " - ").ignore()
testAll()
}
words {
("a c" - "a X c" - "a Y c")
(" " - " -- " - " -- ").default()
(" " - " - " - " - ").ignore()
testAll()
}
}
fun testNewlines() {
words {
("i" - "i_" - "_i")
("-" - "--" - "--").default() // TODO
(" " - " " - " ").trim()
testAll()
}
words {
("_i" - "i_" - "i")
("--" - "--" - "-").default()
(" " - " " - " ").trim()
testAll()
}
words {
("i" - "_i" - "i_")
(" " - "- " - " -").default()
(" " - " " - " ").trim()
testAll()
}
words {
("_i" - "i" - "i_")
("- " - " " - " -").default()
(" " - " " - " ").trim()
testAll()
}
}
}
@@ -32,7 +32,7 @@ class MergeAutoTest : MergeTestBase() {
private fun doUndoTest(seed: Long, runs: Int, maxLength: Int) {
doTest(seed, runs, maxLength) { text1, text2, text3, debugData ->
testN(text1, text2, text3) {
if (changes.size == 0) {
if (changes.isEmpty()) {
assertEquals(text1, text2)
assertEquals(text1, text3)
assertEquals(text2, text3)
@@ -99,7 +99,7 @@ abstract class MergeTestBase : DiffTestCase() {
val editor: EditorEx = viewer.editor
val document: Document = editor.document
private val textEditor = TextEditorProvider.getInstance().getTextEditor(editor);
private val textEditor = TextEditorProvider.getInstance().getTextEditor(editor)
private val undoManager = UndoManager.getInstance(project!!)
fun change(num: Int): TextMergeChange {
@@ -114,7 +114,7 @@ abstract class MergeTestBase : DiffTestCase() {
//
fun runActionByTitle(name: String): Boolean {
val action = actions.filter { name.equals(it.templatePresentation.text) }
val action = actions.filter { name == it.templatePresentation.text }
assertTrue(action.size == 1, action.toString())
return runAction(action[0])
}
@@ -396,7 +396,7 @@ abstract class MergeTestBase : DiffTestCase() {
if (other !is ViewerState) return false
if (!StringUtil.equals(content, other.content)) return false
if (!changes.equals(other.changes)) return false
if (changes != other.changes) return false
return true
}
@@ -411,9 +411,9 @@ abstract class MergeTestBase : DiffTestCase() {
if (other !is ChangeState) return false
if (!StringUtil.equals(content, other.content)) return false
if (!starts.equals(other.starts)) return false
if (!ends.equals(other.ends)) return false
if (!resolved.equals(other.resolved)) return false
if (starts != other.starts) return false
if (ends != other.ends) return false
if (resolved != other.resolved) return false
return true
}
@@ -175,6 +175,7 @@ class LineNumberConvertorCorrectorTest : UsefulTestCase() {
assertEquals(minimumMatched2, counter2)
}
@Suppress("unused")
fun printMatchings() {
for (i in 0..length * 2 - 1) {
val value = convertor.convert1(i)
@@ -34,8 +34,8 @@ class UnifiedFragmentBuilderAutoTest : DiffTestCase() {
doAutoTest(seed, runs) { debugData ->
debugData.put("MaxLength", maxLength)
var text1 = DocumentImpl(generateText(maxLength))
var text2 = DocumentImpl(generateText(maxLength))
val text1 = DocumentImpl(generateText(maxLength))
val text2 = DocumentImpl(generateText(maxLength))
debugData.put("Text1", textToReadableFormat(text1.charsSequence))
debugData.put("Text2", textToReadableFormat(text2.charsSequence))
@@ -38,9 +38,7 @@ public class VfsEventsMerger {
while (true) {
ChangeInfo existingChangeInfo = myChangeInfos.get(fileId);
ChangeInfo newChangeInfo = new ChangeInfo(file, mask, existingChangeInfo);
boolean replaced = existingChangeInfo == null ? myChangeInfos.putIfAbsent(fileId, newChangeInfo) == null
: myChangeInfos.replace(fileId, existingChangeInfo, newChangeInfo);
if (replaced) break;
if(myChangeInfos.put(fileId, newChangeInfo) == existingChangeInfo) break;
}
}
@@ -2,7 +2,7 @@
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog.PluginUpdateInfoPanel">
<grid id="18751" binding="myPanel" layout-manager="GridBagLayout">
<constraints>
<xy x="63" y="44" width="604" height="510"/>
<xy x="63" y="44" width="604" height="522"/>
</constraints>
<properties/>
<border type="none"/>
@@ -13,7 +13,6 @@
<gridbag weightx="1.0" weighty="0.0"/>
</constraints>
<properties>
<preferredSize width="268" height="30"/>
<text resource-bundle="messages/IdeBundle" key="updates.plugins.ready.header"/>
</properties>
</component>
@@ -21,4 +21,5 @@ public class SSHUtil {
public static final Pattern PASSPHRASE_PROMPT = Pattern.compile("Enter passphrase for key \\'(.*)\\':\\s?");
public static final Pattern PASSWORD_PROMPT = Pattern.compile("(.*)\\'s password:\\s?");
public static final String PASSWORD_PROMPT_SUFFIX = "password:";
public static final String CONFIRM_CONNECTION_PROMPT = "Are you sure you want to continue connecting";
}
@@ -23,6 +23,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
// unless stated otherwise, the behavior described in cases is true for 162+
class UpdateStrategyTest {
@Test fun `channel contains no builds`() {
val result = check("IU-145.258", ChannelStatus.RELEASE, """<channel id="IDEA_Release" status="release" licensing="release"/>""")
@@ -150,6 +151,7 @@ class UpdateStrategyTest {
assertBuild("143.2332", result.newBuild)
}
// since 163
@Test fun `updates from the same baseline are preferred (per-release channels)`() {
val result = check("IU-143.2287", ChannelStatus.EAP, """
<channel id="IDEA_143_EAP" status="eap" licensing="eap">