[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / platform / diff-impl / tests / com / intellij / diff / merge / MergeAutoTest.kt
1 // 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.
2 package com.intellij.diff.merge
3
4 import com.intellij.diff.DiffTestCase
5 import com.intellij.diff.tools.util.base.IgnorePolicy
6 import com.intellij.diff.util.Side
7 import com.intellij.diff.util.ThreeSide
8
9 class MergeAutoTest : MergeTestBase() {
10   companion object {
11     private const val RUNS = 10
12     private const val MODIFICATION_CYCLE_COUNT = 5
13     private const val MODIFICATION_CYCLE_SIZE = 3
14     private const val MAX_TEXT_LENGTH = 300
15   }
16
17   fun `test undo - default policy`() {
18     doUndoTest(System.currentTimeMillis(), RUNS, MAX_TEXT_LENGTH, IgnorePolicy.DEFAULT)
19   }
20
21   fun `test undo - trim whitespaces`() {
22     doUndoTest(System.currentTimeMillis(), RUNS, MAX_TEXT_LENGTH, IgnorePolicy.TRIM_WHITESPACES)
23   }
24
25   fun `test undo - ignore whitespaces`() {
26     doUndoTest(System.currentTimeMillis(), RUNS, MAX_TEXT_LENGTH, IgnorePolicy.IGNORE_WHITESPACES)
27   }
28
29   private fun doUndoTest(seed: Long, runs: Int, maxLength: Int, policy: IgnorePolicy) {
30     doTest(seed, runs, maxLength) { text1, text2, text3, debugData ->
31       debugData.put("IgnorePolicy", policy)
32
33       test(text1, text2, text3, -1, policy) {
34         if (changes.isEmpty()) {
35           assertEquals(text1, text2)
36           assertEquals(text1, text3)
37           assertEquals(text2, text3)
38           return@test
39         }
40
41         for (m in 1..MODIFICATION_CYCLE_COUNT) {
42           checkUndo(MODIFICATION_CYCLE_SIZE) {
43             for (n in 1..MODIFICATION_CYCLE_SIZE) {
44               val operation = RNG.nextInt(4)
45               when (operation) {
46                 0 -> doApply()
47                 1 -> doIgnore()
48                 2 -> doTryResolve()
49                 3 -> doModifyText()
50                 else -> fail()
51               }
52               checkChangesRangeOrdering(changes)
53             }
54           }
55         }
56       }
57     }
58   }
59
60   private fun TestBuilder.doApply() {
61     val index = RNG.nextInt(changes.size)
62     val change = changes[index]
63
64     val side = Side.fromLeft(RNG.nextBoolean())
65     val modifier = RNG.nextBoolean()
66
67     command(change) { viewer.replaceChange(change, side, modifier) }
68   }
69
70   private fun TestBuilder.doIgnore() {
71     val index = RNG.nextInt(changes.size)
72     val change = changes[index]
73
74     val side = Side.fromLeft(RNG.nextBoolean())
75     val modifier = RNG.nextBoolean()
76
77     command(change) { viewer.ignoreChange(change, side, modifier) }
78   }
79
80   private fun TestBuilder.doTryResolve() {
81     val index = RNG.nextInt(changes.size)
82     val change = changes[index]
83
84     command(change) { viewer.resolveChangeAutomatically(change, ThreeSide.BASE) }
85   }
86
87   private fun TestBuilder.doModifyText() {
88     val length = document.textLength
89
90     var index1 = 0
91     var index2 = 0
92     if (length != 0) {
93       index1 = RNG.nextInt(length)
94       index2 = index1 + RNG.nextInt(length - index1)
95     }
96
97     val newText = generateText(30)
98
99     write { document.replaceString(index1, index2, newText) }
100   }
101
102   private fun doTest(seed: Long, runs: Int, maxLength: Int, test: (String, String, String, DiffTestCase.DebugData) -> Unit) {
103     doAutoTest(seed, runs) { debugData ->
104       debugData.put("MaxLength", maxLength)
105
106       val text1 = generateText(maxLength)
107       val text2 = generateText(maxLength)
108       val text3 = generateText(maxLength)
109
110       debugData.put("Text1", textToReadableFormat(text1))
111       debugData.put("Text2", textToReadableFormat(text2))
112       debugData.put("Text3", textToReadableFormat(text3))
113
114       test(text1, text2, text3, debugData)
115     }
116   }
117
118   private fun checkChangesRangeOrdering(changes: List<TextMergeChange>) {
119     for (i in 1..changes.size - 1) {
120       val lastEnd = changes[i - 1].getEndLine(ThreeSide.BASE)
121       val start = changes[i].getStartLine(ThreeSide.BASE)
122       assertTrue(lastEnd <= start, "lastEnd: $lastEnd, start: $start")
123     }
124   }
125 }