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) {
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)
}
}
- 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) {
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)
}
}
}
- 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
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
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
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) {
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
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 doLineInnerTest(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)
checkConsistencyLineInner(fragments, before, after)
if (expected != null) checkDiffChanges(diffFragments, expected)
}
- private fun doWordTest(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 (expected != null) checkDiffChanges(fragments, expected)
}
- private fun doCharTest(before: Document, after: Document, matchings: Couple<BitSet>?, expected: List<Change>?, policy: ComparisonPolicy) {
+ 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
}
}
- 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()
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>) {
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 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 convertDiffFragments(fragments: List<DiffFragment>): List<Couple<IntPair>> {
+ return fragments.map { Couple(IntPair(it.startOffset1, it.endOffset1), IntPair(it.startOffset2, it.endOffset2)) }
}
- private fun convertDiffFragments(fragments: List<DiffFragment>): List<Change> {
- return fragments.map { Change(it.startOffset1, it.endOffset1, 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 convertLineFragments(fragments: List<LineFragment>): List<Change> {
- return fragments.map { Change(it.startLine1, it.endLine1, 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) {
// 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, 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)
}
try {
isExecuted = true
- val change = changes(policy)
- val matchings = matchings(policy)
- assertTrue(change != null || matchings != null)
-
- when (type) {
- TestType.LINE -> doLineTest(before!!, after!!, matchings, change, policy)
- TestType.LINE_INNER -> {
- doLineInnerTest(before!!, after!!, matchings, change, policy)
- doWordTest(before!!, after!!, matchings, change, policy)
+ 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(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)
}
- 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)
+ }
+ 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)
}
}
}
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))
- }
- }
-
- 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")
+ return Data(parseMatching(before),
+ if (base != null) parseMatching(base) else null,
+ parseMatching(after))
}
-
-
- 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))
}
// 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
+ }
+ }
}