diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/InlayParameterHintsTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/InlayParameterHintsTest.kt index ceba1745faa7..d60c2a6dd8b1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/InlayParameterHintsTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/InlayParameterHintsTest.kt @@ -88,7 +88,8 @@ class InlayAssert(private val file: PsiFile, val inlays: List) { 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) { assertThat(hintNames).isEqualTo(expectedHintNames) - val wordsAfter = hintOffsets.mapNotNull { file.findElementAt(it) }.map { it.text } - + val wordsAfter = elements.map { it.text } assertThat(wordsAfter).isEqualTo(expectedWordsAfter) } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt index d695a36345be..ff2227789255 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/inlays/JavaParameterNameHintsTest.kt @@ -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") } diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java b/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java index eec26d3f1e25..a685de3484a9 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/ByWord.java @@ -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); } } diff --git a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.java b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.java index 7914771fad5c..48ed3629fc71 100644 --- a/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/comparison/TrimUtil.java @@ -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); + } } diff --git a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt index 8145b2a415a7..2172ab6d32de 100644 --- a/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/DiffTestCase.kt @@ -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(val data1: T, val data2: T, val data3: T) { + open class Trio(val data1: T, val data2: T, val data3: T) { companion object { - fun from(f: (ThreeSide) -> V): Trio = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT)) + fun from(f: (ThreeSide) -> V): Trio = Trio(f(ThreeSide.LEFT), f(ThreeSide.BASE), f(ThreeSide.RIGHT)) } - fun map(f: (T) -> V): Trio = Trio(f(data1), f(data2), f(data3)) + fun map(f: (T) -> V): Trio = Trio(f(data1), f(data2), f(data3)) - fun map(f: (T, ThreeSide) -> V): Trio = Trio(f(data1, ThreeSide.LEFT), f(data2, ThreeSide.BASE), f(data3, ThreeSide.RIGHT)) + fun map(f: (T, ThreeSide) -> V): Trio = 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 } } } \ No newline at end of file diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt index 4de112cd371b..f46fc7f5ea35 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilAutoTest.kt @@ -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, 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, 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, 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, policy: ComparisonPolicy, skipNewline: Boolean) { + private fun checkValidRanges(text1: CharSequence, text2: CharSequence, fragments: List, 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, policy: ComparisonPolicy) { - val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT + private fun checkValidRanges3(text1: Document, text2: Document, text3: Document, fragments: List, 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, policy: ComparisonPolicy) { - val ignoreSpaces = policy !== ComparisonPolicy.DEFAULT + private fun checkValidRanges3(text1: CharSequence, text2: CharSequence, text3: CharSequence, fragments: List, 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, 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? { diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt index 1559310cec45..ec32651c510b 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/ComparisonUtilTestBase.kt @@ -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?, expected: List?, policy: ComparisonPolicy) { + private fun doLineTest(text: Couple, matchings: Couple?, expected: List>?, 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?, expected: List?, policy: ComparisonPolicy) { + private fun doLineInnerTest(text: Couple, matchings: Couple?, expected: List>?, 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?, expected: List?, policy: ComparisonPolicy) { + private fun doWordTest(text: Couple, matchings: Couple?, expected: List>?, 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, matchings: Trio?, expected: List>?, 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, matchings: Couple?, expected: List>?, 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?, policy: ComparisonPolicy) { + private fun doSplitterTest(text: Couple, + squash: Boolean, + trim: Boolean, + expected: List>?, + 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, before: Document, after: Document) { + private fun checkConsistencyLineInner(fragments: List, 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, expected: List) { + private fun checkConsistency(fragments: List) { + 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, expected: List>) { val changes = convertLineFragments(fragments) assertOrderedEquals(changes, expected) } - private fun checkDiffChanges(fragments: List, expected: List) { + private fun checkDiffChanges(fragments: List, expected: List>) { val changes = convertDiffFragments(fragments) assertOrderedEquals(changes, expected) } + private fun checkMergeChanges(fragments: List, expected: List>) { + val changes = convertMergeFragments(fragments) + assertOrderedEquals(changes, expected) + } + private fun checkLineMatching(fragments: List, matchings: Couple) { 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, matchings: Couple) { @@ -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): List { - return fragments.map { Change(it.startOffset1, it.endOffset1, it.startOffset2, it.endOffset2) } + private fun checkMergeMatching(fragments: List, matchings: Trio) { + 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): List { - return fragments.map { Change(it.startLine1, it.endLine1, it.startLine2, it.endLine2) } + private fun convertDiffFragments(fragments: List): List> { + return fragments.map { Couple(IntPair(it.startOffset1, it.endOffset1), IntPair(it.startOffset2, it.endOffset2)) } + } + + private fun convertLineFragments(fragments: List): List> { + return fragments.map { Couple(IntPair(it.startLine1, it.endLine1), IntPair(it.startLine2, it.endLine2)) } + } + + private fun convertMergeFragments(fragments: List): List> { + 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? = null - private var trimChanges: List? = null - private var ignoreChanges: List? = null - - private var defaultMatching: Couple? = null - private var trimMatching: Couple? = null - private var ignoreMatching: Couple? = null + private var text: Data = Data() + private var changes: PolicyData>> = PolicyData() + private var matchings: PolicyData> = PolicyData() private var shouldSquash: Boolean = false private var shouldTrim: Boolean = false - private fun changes(policy: ComparisonPolicy): List? = when (policy) { - ComparisonPolicy.IGNORE_WHITESPACES -> ignoreChanges ?: trimChanges ?: defaultChanges - ComparisonPolicy.TRIM_WHITESPACES -> trimChanges ?: defaultChanges - ComparisonPolicy.DEFAULT -> defaultChanges - } - - private fun matchings(policy: ComparisonPolicy): Couple? = 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 { + private fun parseMatching(before: String, after: String, base: String?): Data { 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): 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): 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): 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 { 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 { 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 { 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(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 { + assert(isTwoSide()) + return Couple(before!!, after!!) + } + + fun asTrio(): Trio { + assert(isThreeSide()) + return Trio(before!!, base!!, after!!) } } + + private data class PolicyData(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 + } + } } diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt index c5c299bd593a..17511441264e 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/MergeResolveUtilTest.kt @@ -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") } } diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/WordComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/WordComparisonUtilTest.kt index 21407c1afabd..c6c1e115a1ed 100644 --- a/platform/diff-impl/tests/com/intellij/diff/comparison/WordComparisonUtilTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/WordComparisonUtilTest.kt @@ -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<>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)) diff --git a/platform/diff-impl/tests/com/intellij/diff/comparison/WordMergeComparisonUtilTest.kt b/platform/diff-impl/tests/com/intellij/diff/comparison/WordMergeComparisonUtilTest.kt new file mode 100644 index 000000000000..9268734d7b8f --- /dev/null +++ b/platform/diff-impl/tests/com/intellij/diff/comparison/WordMergeComparisonUtilTest.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt index 9002b6adf776..cf09a556ec03 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeAutoTest.kt @@ -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) diff --git a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt index 132870446311..aa12d8eea670 100644 --- a/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt +++ b/platform/diff-impl/tests/com/intellij/diff/merge/MergeTestBase.kt @@ -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 } diff --git a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/LineNumberConvertorCorrectorTest.kt b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/LineNumberConvertorCorrectorTest.kt index 14b14fe41e93..82d67e94e224 100644 --- a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/LineNumberConvertorCorrectorTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/LineNumberConvertorCorrectorTest.kt @@ -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) diff --git a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderAutoTest.kt b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderAutoTest.kt index 3d8dea4609b4..6f729d03a726 100644 --- a/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderAutoTest.kt +++ b/platform/diff-impl/tests/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilderAutoTest.kt @@ -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)) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java b/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java index 7bc171f5395b..dc8fef174a11 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/VfsEventsMerger.java @@ -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; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoPanel.form b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoPanel.form index 0e86badb08c5..0408bfaeabc8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoPanel.form +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoPanel.form @@ -2,7 +2,7 @@
- + @@ -13,7 +13,6 @@ - diff --git a/platform/platform-impl/src/com/intellij/ssh/SSHUtil.java b/platform/platform-impl/src/com/intellij/ssh/SSHUtil.java index bb61cd084f19..9142b15d7041 100644 --- a/platform/platform-impl/src/com/intellij/ssh/SSHUtil.java +++ b/platform/platform-impl/src/com/intellij/ssh/SSHUtil.java @@ -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"; } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.kt b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.kt index a3c7e4764dde..bf3e0a1d0e0d 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.kt +++ b/platform/platform-tests/testSrc/com/intellij/ide/updates/UpdateStrategyTest.kt @@ -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, """""") @@ -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, """