IDEA-77478 diff: support by-character diff highlighting

This commit is contained in:
Aleksey Pivovarov
2018-10-20 13:14:19 +03:00
parent 1c07331c45
commit eeee5b698f
9 changed files with 184 additions and 55 deletions
@@ -5,6 +5,7 @@ import com.intellij.diff.DiffContentFactory;
import com.intellij.diff.DiffManager;
import com.intellij.diff.DiffRequestPanel;
import com.intellij.diff.comparison.ComparisonManagerImpl;
import com.intellij.diff.comparison.InnerFragmentsPolicy;
import com.intellij.diff.contents.DocumentContent;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.tools.fragmented.UnifiedDiffTool;
@@ -389,13 +390,14 @@ class PreviewDiffPanel extends BorderLayoutPanel implements Disposable, PreviewT
@NotNull
private static DiffUserDataKeysEx.DiffComputer getDiffComputer(@NotNull Collection<? extends Range> ranges) {
return (text1, text2, policy, innerChanges, indicator) -> {
InnerFragmentsPolicy fragmentsPolicy = innerChanges ? InnerFragmentsPolicy.WORDS : InnerFragmentsPolicy.NONE;
LineOffsets offsets1 = LineOffsetsUtil.create(text1);
LineOffsets offsets2 = LineOffsetsUtil.create(text2);
List<LineFragment> result = new ArrayList<>();
ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl();
for (Range range : ranges) {
result.addAll(comparisonManager.compareLinesInner(range, text1, text2, offsets1, offsets2, policy, innerChanges, indicator));
result.addAll(comparisonManager.compareLinesInner(range, text1, text2, offsets1, offsets2, policy, fragmentsPolicy, indicator));
}
return result;
};
@@ -0,0 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.diff.comparison;
public enum InnerFragmentsPolicy {
NONE,
WORDS,
CHARS
}
@@ -16,7 +16,9 @@
package com.intellij.diff.comparison;
import com.intellij.diff.comparison.iterables.DiffIterable;
import com.intellij.diff.comparison.iterables.DiffIterableUtil;
import com.intellij.diff.comparison.iterables.FairDiffIterable;
import com.intellij.diff.util.IntPair;
import com.intellij.diff.util.Range;
import com.intellij.openapi.progress.ProgressIndicator;
import gnu.trove.TIntArrayList;
@@ -55,6 +57,32 @@ public class ByChar {
return matchAdjustmentSpaces(chars1, chars2, text1, text2, nonSpaceChanges, indicator);
}
@NotNull
public static DiffIterable compareTrimWhitespaces(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ProgressIndicator indicator) {
FairDiffIterable iterable = compareTwoStep(text1, text2, indicator);
IntPair trim1 = TrimUtil.trim(text1, 0, text1.length());
IntPair trim2 = TrimUtil.trim(text2, 0, text2.length());
List<Range> ranges = new ArrayList<>();
for (Range ch : iterable.iterateChanges()) {
int start1 = Math.max(ch.start1, trim1.val1);
int end1 = Math.min(ch.end1, trim1.val2);
int start2 = Math.max(ch.start2, trim2.val1);
int end2 = Math.min(ch.end2, trim2.val2);
if (end1 < start1) start1 = end1 = ch.start1;
if (end2 < start2) start2 = end2 = ch.start2;
if (start1 != end1 || start2 != end2) {
ranges.add(new Range(start1, end1, start2, end2));
}
}
return DiffIterableUtil.create(ranges, text1.length(), text2.length());
}
@NotNull
public static DiffIterable compareIgnoreWhitespaces(@NotNull CharSequence text1,
@NotNull CharSequence text2,
@@ -127,7 +127,7 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<LineFragment> lineFragments = compareLines(text1, text2, policy, indicator);
return createInnerFragments(lineFragments, text1, text2, policy, indicator);
return createInnerFragments(lineFragments, text1, text2, policy, InnerFragmentsPolicy.WORDS, indicator);
}
@NotNull
@@ -136,11 +136,11 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull LineOffsets lineOffsets1,
@NotNull LineOffsets lineOffsets2,
@NotNull ComparisonPolicy policy,
boolean innerFragments,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<LineFragment> lineFragments = compareLines(text1, text2, lineOffsets1, lineOffsets2, policy, indicator);
if (innerFragments) {
return createInnerFragments(lineFragments, text1, text2, policy, indicator);
if (fragmentsPolicy != InnerFragmentsPolicy.NONE) {
return createInnerFragments(lineFragments, text1, text2, policy, fragmentsPolicy, indicator);
}
else {
return lineFragments;
@@ -154,11 +154,11 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull LineOffsets lineOffsets1,
@NotNull LineOffsets lineOffsets2,
@NotNull ComparisonPolicy policy,
boolean innerFragments,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<LineFragment> lineFragments = compareLines(range, text1, text2, lineOffsets1, lineOffsets2, policy, indicator);
if (innerFragments) {
return createInnerFragments(lineFragments, text1, text2, policy, indicator);
if (fragmentsPolicy != InnerFragmentsPolicy.NONE) {
return createInnerFragments(lineFragments, text1, text2, policy, fragmentsPolicy, indicator);
}
else {
return lineFragments;
@@ -169,6 +169,7 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ComparisonPolicy policy,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator) {
List<LineFragment> result = new ArrayList<>(lineFragments.size());
@@ -179,7 +180,7 @@ public class ComparisonManagerImpl extends ComparisonManager {
try {
// Do not try to build fine blocks after few fails
boolean tryComputeDifferences = tooBigChunksCount < FilesTooBigForDiffException.MAX_BAD_LINES;
result.addAll(createInnerFragments(fragment, text1, text2, policy, indicator, tryComputeDifferences));
result.addAll(createInnerFragments(fragment, text1, text2, policy, fragmentsPolicy, indicator, tryComputeDifferences));
}
catch (DiffTooBigException e) {
result.add(fragment);
@@ -195,8 +196,13 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull CharSequence text1,
@NotNull CharSequence text2,
@NotNull ComparisonPolicy policy,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator,
boolean tryComputeDifferences) throws DiffTooBigException {
if (fragmentsPolicy == InnerFragmentsPolicy.NONE) {
return singletonList(fragment);
}
CharSequence subSequence1 = text1.subSequence(fragment.getStartOffset1(), fragment.getEndOffset1());
CharSequence subSequence2 = text2.subSequence(fragment.getStartOffset2(), fragment.getEndOffset2());
@@ -212,6 +218,23 @@ public class ComparisonManagerImpl extends ComparisonManager {
if (!tryComputeDifferences) return singletonList(fragment);
if (fragmentsPolicy == InnerFragmentsPolicy.WORDS) {
return createInnerWordFragments(fragment, subSequence1, subSequence2, policy, indicator);
}
else if (fragmentsPolicy == InnerFragmentsPolicy.CHARS) {
return createInnerCharFragments(fragment, subSequence1, subSequence2, policy, indicator);
}
else {
throw new IllegalArgumentException(fragmentsPolicy.name());
}
}
@NotNull
private static List<LineFragment> createInnerWordFragments(@NotNull LineFragment fragment,
@NotNull CharSequence subSequence1,
@NotNull CharSequence subSequence2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<ByWord.LineBlock> lineBlocks = ByWord.compareAndSplit(subSequence1, subSequence2, policy, indicator);
assert lineBlocks.size() != 0;
@@ -241,6 +264,27 @@ public class ComparisonManagerImpl extends ComparisonManager {
return chunks;
}
@NotNull
private static List<LineFragment> createInnerCharFragments(@NotNull LineFragment fragment,
@NotNull CharSequence subSequence1,
@NotNull CharSequence subSequence2,
@NotNull ComparisonPolicy policy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
DiffIterable iterable;
if (policy == ComparisonPolicy.DEFAULT) {
iterable = ByChar.compareTwoStep(subSequence1, subSequence2, indicator);
}
else if (policy == ComparisonPolicy.TRIM_WHITESPACES) {
iterable = ByChar.compareTrimWhitespaces(subSequence1, subSequence2, indicator);
}
else {
iterable = ByChar.compareIgnoreWhitespaces(subSequence1, subSequence2, indicator);
}
List<DiffFragment> innerChanges = convertIntoDiffFragments(iterable);
return singletonList(new LineFragmentImpl(fragment, innerChanges));
}
@NotNull
@Override
@Deprecated
@@ -532,12 +576,12 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull LineOffsets lineOffsets2,
@NotNull BitSet ignored1,
@NotNull BitSet ignored2,
boolean innerFragments,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
Range range = new Range(0, lineOffsets1.getLineCount(),
0, lineOffsets2.getLineCount());
return compareLinesWithIgnoredRanges(range, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2,
innerFragments, indicator);
fragmentsPolicy, indicator);
}
/**
@@ -551,7 +595,7 @@ public class ComparisonManagerImpl extends ComparisonManager {
@NotNull LineOffsets lineOffsets2,
@NotNull BitSet ignored1,
@NotNull BitSet ignored2,
boolean innerFragments,
@NotNull InnerFragmentsPolicy fragmentsPolicy,
@NotNull ProgressIndicator indicator) throws DiffTooBigException {
List<CharSequence> lineTexts1 = getNotIgnoredLineContents(range.start1, range.end1, text1, lineOffsets1, ignored1);
List<CharSequence> lineTexts2 = getNotIgnoredLineContents(range.start2, range.end2, text2, lineOffsets2, ignored2);
@@ -566,8 +610,8 @@ public class ComparisonManagerImpl extends ComparisonManager {
List<LineFragment> lineFragments = convertIntoLineFragments(range, lineOffsets1, lineOffsets2, trimmedIterable);
if (innerFragments) {
lineFragments = createInnerFragments(lineFragments, text1, text2, ComparisonPolicy.DEFAULT, indicator);
if (fragmentsPolicy != InnerFragmentsPolicy.NONE) {
lineFragments = createInnerFragments(lineFragments, text1, text2, ComparisonPolicy.DEFAULT, fragmentsPolicy, indicator);
}
return ContainerUtil.mapNotNull(lineFragments, fragment -> {
@@ -15,12 +15,14 @@
*/
package com.intellij.diff.tools.util.base;
import com.intellij.diff.comparison.InnerFragmentsPolicy;
import org.jetbrains.annotations.NotNull;
public enum HighlightPolicy {
BY_LINE("Highlight lines"),
BY_WORD("Highlight words"),
BY_WORD_SPLIT("Highlight split changes"),
BY_CHAR("Highlight symbols"),
DO_NOT_HIGHLIGHT("Do not highlight");
@NotNull private final String myText;
@@ -39,10 +41,26 @@ public enum HighlightPolicy {
}
public boolean isFineFragments() {
return this == BY_WORD || this == BY_WORD_SPLIT;
return getFragmentsPolicy() != InnerFragmentsPolicy.NONE;
}
public boolean isShouldSquash() {
return this == BY_WORD || this == BY_LINE;
return this != BY_WORD_SPLIT;
}
@NotNull
public InnerFragmentsPolicy getFragmentsPolicy() {
switch (this) {
case BY_WORD:
case BY_WORD_SPLIT:
return InnerFragmentsPolicy.WORDS;
case BY_CHAR:
return InnerFragmentsPolicy.CHARS;
case BY_LINE:
case DO_NOT_HIGHLIGHT:
return InnerFragmentsPolicy.NONE;
default:
throw new IllegalArgumentException(this.name());
}
}
}
@@ -17,6 +17,7 @@ package com.intellij.diff.tools.util.text;
import com.intellij.diff.comparison.ComparisonManagerImpl;
import com.intellij.diff.comparison.ComparisonPolicy;
import com.intellij.diff.comparison.InnerFragmentsPolicy;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.tools.util.base.HighlightPolicy;
import com.intellij.diff.tools.util.base.IgnorePolicy;
@@ -41,7 +42,8 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen
private static final Logger LOG = Logger.getInstance(SimpleTextDiffProvider.class);
private static final IgnorePolicy[] IGNORE_POLICIES = {DEFAULT, TRIM_WHITESPACES, IGNORE_WHITESPACES, IGNORE_WHITESPACES_CHUNKS};
private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, DO_NOT_HIGHLIGHT};
private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, BY_CHAR, DO_NOT_HIGHLIGHT};
private static final HighlightPolicy[] CUSTOM_COMPUTER_HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, DO_NOT_HIGHLIGHT};
@Nullable private final DiffComputer myDiffComputer;
@@ -55,7 +57,8 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen
@NotNull Runnable rediff,
@NotNull Disposable disposable,
@Nullable DiffComputer diffComputer) {
this(settings, rediff, disposable, diffComputer, IGNORE_POLICIES, HIGHLIGHT_POLICIES);
this(settings, rediff, disposable, diffComputer, IGNORE_POLICIES,
diffComputer != null ? CUSTOM_COMPUTER_HIGHLIGHT_POLICIES : HIGHLIGHT_POLICIES);
}
private SimpleTextDiffProvider(@NotNull TextDiffSettings settings,
@@ -92,7 +95,7 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen
@NotNull HighlightPolicy highlightPolicy,
@NotNull ProgressIndicator indicator) {
ComparisonPolicy policy = ignorePolicy.getComparisonPolicy();
boolean innerFragments = highlightPolicy.isFineFragments();
InnerFragmentsPolicy fragmentsPolicy = highlightPolicy.getFragmentsPolicy();
if (diffComputer != null && linesRanges != null) {
LOG.error(new Throwable("Unsupported operation: ranged diff with custom DiffComputer - " + diffComputer));
@@ -101,12 +104,12 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen
ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl();
if (linesRanges == null) {
if (diffComputer != null) {
List<LineFragment> fragments = diffComputer.compute(text1, text2, policy, innerFragments, indicator);
List<LineFragment> fragments = diffComputer.compute(text1, text2, policy, fragmentsPolicy != InnerFragmentsPolicy.NONE, indicator);
return Collections.singletonList(fragments);
}
else {
List<LineFragment> fragments = comparisonManager.compareLinesInner(text1, text2, lineOffsets1, lineOffsets2,
policy, innerFragments, indicator);
policy, fragmentsPolicy, indicator);
return Collections.singletonList(fragments);
}
}
@@ -114,7 +117,7 @@ public class SimpleTextDiffProvider extends TwosideTextDiffProviderBase implemen
List<List<LineFragment>> result = new ArrayList<>();
for (Range range : linesRanges) {
result.add(comparisonManager.compareLinesInner(range, text1, text2, lineOffsets1, lineOffsets2,
policy, innerFragments, indicator));
policy, fragmentsPolicy, indicator));
}
return result;
}
@@ -16,6 +16,7 @@
package com.intellij.diff.tools.util.text;
import com.intellij.diff.comparison.ComparisonManagerImpl;
import com.intellij.diff.comparison.InnerFragmentsPolicy;
import com.intellij.diff.contents.DiffContent;
import com.intellij.diff.fragments.LineFragment;
import com.intellij.diff.lang.DiffIgnoredRangeProvider;
@@ -44,7 +45,7 @@ import static com.intellij.diff.tools.util.base.IgnorePolicy.*;
public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implements TwosideTextDiffProvider {
private static final IgnorePolicy[] IGNORE_POLICIES = {DEFAULT, TRIM_WHITESPACES, IGNORE_WHITESPACES, IGNORE_WHITESPACES_CHUNKS, FORMATTING};
private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, DO_NOT_HIGHLIGHT};
private static final HighlightPolicy[] HIGHLIGHT_POLICIES = {BY_LINE, BY_WORD, BY_WORD_SPLIT, BY_CHAR, DO_NOT_HIGHLIGHT};
@Nullable private final Project myProject;
@NotNull private final DiffContent myContent1;
@@ -137,7 +138,7 @@ public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implement
@Nullable List<Range> linesRanges,
@NotNull HighlightPolicy highlightPolicy,
@NotNull ProgressIndicator indicator) {
boolean innerFragments = highlightPolicy.isFineFragments();
InnerFragmentsPolicy fragmentsPolicy = highlightPolicy.getFragmentsPolicy();
List<TextRange> ignoredRanges1 = myProvider.getIgnoredRanges(myProject, text1, myContent1);
List<TextRange> ignoredRanges2 = myProvider.getIgnoredRanges(myProject, text2, myContent2);
@@ -148,14 +149,14 @@ public class SmartTextDiffProvider extends TwosideTextDiffProviderBase implement
ComparisonManagerImpl comparisonManager = ComparisonManagerImpl.getInstanceImpl();
if (linesRanges == null) {
List<LineFragment> fragments = comparisonManager.compareLinesWithIgnoredRanges(text1, text2, lineOffsets1, lineOffsets2,
ignored1, ignored2, innerFragments, indicator);
ignored1, ignored2, fragmentsPolicy, indicator);
return Collections.singletonList(fragments);
}
else {
List<List<LineFragment>> result = new ArrayList<>();
for (Range range : linesRanges) {
result.add(comparisonManager.compareLinesWithIgnoredRanges(range, text1, text2, lineOffsets1, lineOffsets2,
ignored1, ignored2, innerFragments, indicator));
ignored1, ignored2, fragmentsPolicy, indicator));
}
return result;
}
@@ -23,6 +23,7 @@ import com.intellij.diff.fragments.MergeLineFragment
import com.intellij.diff.fragments.MergeWordFragment
import com.intellij.diff.tools.util.base.HighlightPolicy
import com.intellij.diff.tools.util.base.IgnorePolicy
import com.intellij.diff.tools.util.text.LineOffsetsUtil
import com.intellij.diff.util.DiffUtil
import com.intellij.diff.util.Range
import com.intellij.diff.util.ThreeSide
@@ -69,78 +70,90 @@ class ComparisonUtilAutoTest : HeavyDiffTestCase() {
}
private fun doTestLine(seed: Long, runs: Int, maxLength: Int) {
val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val ignorePolicies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val fragmentsPolicies = listOf(InnerFragmentsPolicy.WORDS, InnerFragmentsPolicy.CHARS)
doTest(seed, runs, maxLength, policies) { text1, text2, policy, debugData ->
doTest(seed, runs, maxLength, ignorePolicies, fragmentsPolicies) { text1, text2, ignorePolicy, fragmentsPolicy, debugData ->
val sequence1 = text1.charsSequence
val sequence2 = text2.charsSequence
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, policy, INDICATOR)
val lineOffsets1 = LineOffsetsUtil.create(sequence1)
val lineOffsets2 = LineOffsetsUtil.create(sequence2)
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, lineOffsets1, lineOffsets2, ignorePolicy, fragmentsPolicy, INDICATOR)
debugData.put("Fragments", fragments)
checkResultLine(text1, text2, fragments, policy, true)
checkResultLine(text1, text2, fragments, ignorePolicy, true)
}
}
private fun doTestLineSquashed(seed: Long, runs: Int, maxLength: Int) {
val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val ignorePolicies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val fragmentsPolicies = listOf(InnerFragmentsPolicy.WORDS, InnerFragmentsPolicy.CHARS)
doTest(seed, runs, maxLength, policies) { text1, text2, policy, debugData ->
doTest(seed, runs, maxLength, ignorePolicies, fragmentsPolicies) { text1, text2, ignorePolicy, fragmentsPolicy, debugData ->
val sequence1 = text1.charsSequence
val sequence2 = text2.charsSequence
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, policy, INDICATOR)
val lineOffsets1 = LineOffsetsUtil.create(sequence1)
val lineOffsets2 = LineOffsetsUtil.create(sequence2)
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, lineOffsets1, lineOffsets2, ignorePolicy, fragmentsPolicy, INDICATOR)
debugData.put("Fragments", fragments)
val squashedFragments = MANAGER.squash(fragments)
debugData.put("Squashed Fragments", squashedFragments)
checkResultLine(text1, text2, squashedFragments, policy, false)
checkResultLine(text1, text2, squashedFragments, ignorePolicy, false)
}
}
private fun doTestLineTrimSquashed(seed: Long, runs: Int, maxLength: Int) {
val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val ignorePolicies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val fragmentsPolicies = listOf(InnerFragmentsPolicy.WORDS, InnerFragmentsPolicy.CHARS)
doTest(seed, runs, maxLength, policies) { text1, text2, policy, debugData ->
doTest(seed, runs, maxLength, ignorePolicies, fragmentsPolicies) { text1, text2, ignorePolicy, fragmentsPolicy, debugData ->
val sequence1 = text1.charsSequence
val sequence2 = text2.charsSequence
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, policy, INDICATOR)
val lineOffsets1 = LineOffsetsUtil.create(sequence1)
val lineOffsets2 = LineOffsetsUtil.create(sequence2)
val fragments = MANAGER.compareLinesInner(sequence1, sequence2, lineOffsets1, lineOffsets2, ignorePolicy, fragmentsPolicy, INDICATOR)
debugData.put("Fragments", fragments)
val processed = MANAGER.processBlocks(fragments, sequence1, sequence2, policy, true, true)
val processed = MANAGER.processBlocks(fragments, sequence1, sequence2, ignorePolicy, true, true)
debugData.put("Processed Fragments", processed)
checkResultLine(text1, text2, processed, policy, false)
checkResultLine(text1, text2, processed, ignorePolicy, false)
}
}
private fun doTestChar(seed: Long, runs: Int, maxLength: Int) {
val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.IGNORE_WHITESPACES)
val ignorePolicies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.IGNORE_WHITESPACES)
doTest(seed, runs, maxLength, policies) { text1, text2, policy, debugData ->
doTest(seed, runs, maxLength, ignorePolicies) { text1, text2, ignorePolicy, debugData ->
val sequence1 = text1.charsSequence
val sequence2 = text2.charsSequence
val fragments = MANAGER.compareChars(sequence1, sequence2, policy, INDICATOR)
val fragments = MANAGER.compareChars(sequence1, sequence2, ignorePolicy, INDICATOR)
debugData.put("Fragments", fragments)
checkResultChar(sequence1, sequence2, fragments, policy)
checkResultChar(sequence1, sequence2, fragments, ignorePolicy)
}
}
private fun doTestWord(seed: Long, runs: Int, maxLength: Int) {
val policies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
val ignorePolicies = listOf(ComparisonPolicy.DEFAULT, ComparisonPolicy.TRIM_WHITESPACES, ComparisonPolicy.IGNORE_WHITESPACES)
doTest(seed, runs, maxLength, policies) { text1, text2, policy, debugData ->
doTest(seed, runs, maxLength, ignorePolicies) { text1, text2, ignorePolicy, debugData ->
val sequence1 = text1.charsSequence
val sequence2 = text2.charsSequence
val fragments = MANAGER.compareWords(sequence1, sequence2, policy, INDICATOR)
val fragments = MANAGER.compareWords(sequence1, sequence2, ignorePolicy, INDICATOR)
debugData.put("Fragments", fragments)
checkResultWord(sequence1, sequence2, fragments, policy)
checkResultWord(sequence1, sequence2, fragments, ignorePolicy)
}
}
@@ -218,12 +231,24 @@ class ComparisonUtilAutoTest : HeavyDiffTestCase() {
}
private fun doTest(seed: Long, runs: Int, maxLength: Int, policies: List<ComparisonPolicy>,
private fun doTest(seed: Long, runs: Int, maxLength: Int,
ignorePolicies: List<ComparisonPolicy>, fragmentsPolicies: List<InnerFragmentsPolicy>,
test: (Document, Document, ComparisonPolicy, InnerFragmentsPolicy, DiffTestCase.DebugData) -> Unit) {
doTest(seed, runs, maxLength, ignorePolicies) { text1, text2, ignorePolicy, debugData ->
for (fragmentsPolicy in fragmentsPolicies) {
debugData.put("Inner Policy", fragmentsPolicy)
test(text1, text2, ignorePolicy, fragmentsPolicy, debugData)
}
}
}
private fun doTest(seed: Long, runs: Int, maxLength: Int,
ignorePolicies: List<ComparisonPolicy>,
test: (Document, Document, ComparisonPolicy, DiffTestCase.DebugData) -> Unit) {
doTest(seed, runs, maxLength) { text1, text2, debugData ->
for (comparisonPolicy in policies) {
debugData.put("Policy", comparisonPolicy)
test(text1, text2, comparisonPolicy, debugData)
for (ignorePolicy in ignorePolicies) {
debugData.put("Ignore Policy", ignorePolicy)
test(text1, text2, ignorePolicy, debugData)
}
}
}
@@ -557,13 +557,13 @@ class IgnoreComparisonUtilTest : DiffTestCase() {
val result1: String = result1.filterNot { it == '.' }
val result2: String = result2.filterNot { it == '.' }
private var inner = true
private var innerPolicy = InnerFragmentsPolicy.WORDS
private var changedLinesNumber: IntPair? = null
private var range: Range? = null
private var changedLines: List<Couple<IntPair>>? = null
fun noInnerChanges(): Test {
inner = false
innerPolicy = InnerFragmentsPolicy.NONE
return this
}
@@ -601,10 +601,10 @@ class IgnoreComparisonUtilTest : DiffTestCase() {
val lineOffsets2 = LineOffsetsUtil.create(text2)
val result = if (range != null) {
MANAGER.compareLinesWithIgnoredRanges(range!!, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, inner, INDICATOR)
MANAGER.compareLinesWithIgnoredRanges(range!!, text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, innerPolicy, INDICATOR)
}
else {
MANAGER.compareLinesWithIgnoredRanges(text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, inner, INDICATOR)
MANAGER.compareLinesWithIgnoredRanges(text1, text2, lineOffsets1, lineOffsets2, ignored1, ignored2, innerPolicy, INDICATOR)
}
val expected = Couple(parseExpected(result1), parseExpected(result2))