[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / platform / diff-impl / tests / com / intellij / diff / tools / fragmented / LineNumberConvertorCorrectorTest.kt
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.diff.tools.fragmented
17
18 import com.intellij.diff.util.Side
19 import junit.framework.TestCase
20
21 class LineNumberConvertorCorrectorTest : TestCase() {
22   fun testUnmodified() {
23     doTest(
24       {
25         equal(0, 0, 10, Side.LEFT)
26         equal(0, 0, 12, Side.RIGHT)
27       },
28       {
29         checkStrictSymmetrical()
30         ensureMatchedCount(10, 12)
31       }
32     )
33   }
34
35   fun testEqual1() {
36     doTest(
37       {
38         equal(0, 0, 10, Side.LEFT)
39         equal(0, 0, 10, Side.RIGHT)
40       },
41       {
42         change(4, 3, 5, Side.LEFT)
43
44         checkStrictSymmetrical()
45         ensureMatchedCount(12, 7)
46       }
47     )
48   }
49
50   fun testEqual2() {
51     doTest(
52       {
53         equal(0, 0, 10, Side.LEFT)
54         equal(0, 0, 10, Side.RIGHT)
55       },
56       {
57         change(4, 5, 3, Side.RIGHT)
58
59         checkStrictSymmetrical()
60         ensureMatchedCount(5, 8)
61       }
62     )
63   }
64
65   fun testEqual3() {
66     doTest(
67       {
68         equal(0, 0, 10, Side.LEFT)
69         equal(0, 0, 10, Side.RIGHT)
70       },
71       {
72         change(4, 3, 3, Side.LEFT)
73
74         checkStrictSymmetrical()
75         ensureMatchedCount(10, 7)
76       }
77     )
78   }
79
80   fun testEqual4() {
81     doTest(
82       {
83         equal(0, 0, 15, Side.LEFT)
84         equal(0, 0, 15, Side.RIGHT)
85       },
86       {
87         change(4, 3, 5, Side.LEFT)
88         checkStrictSymmetrical()
89         change(1, 2, 1, Side.RIGHT)
90         checkStrictSymmetrical()
91         change(12, 3, 1, Side.LEFT)
92         checkStrictSymmetrical()
93
94         ensureMatchedCount(13, 8)
95       }
96     )
97   }
98
99   fun testInsideModifiedRange() {
100     doTest(
101       {
102         equal(0, 0, 15, Side.LEFT)
103         equal(0, 0, 15, Side.RIGHT)
104       },
105       {
106         change(0, 10, 15, Side.LEFT)
107         checkStrictSymmetrical()
108         change(0, 8, 6, Side.LEFT)
109         checkStrictSymmetrical()
110         change(2, 4, 2, Side.LEFT)
111         checkStrictSymmetrical()
112       }
113     )
114   }
115
116   //
117   // Impl
118   //
119
120   private fun doTest(prepare: TestBuilder.() -> Unit, check: Test.() -> Unit) {
121     val builder = TestBuilder()
122     builder.prepare()
123     val test = builder.finish()
124     test.check()
125   }
126
127   private class TestBuilder {
128     private val builder1 = LineNumberConvertor.Builder()
129     private val builder2 = LineNumberConvertor.Builder()
130     private var maxLength = 0 // search for strict matchings in this boundaries (*2 - just in case)
131
132     fun equal(onesideStart: Int, twosideStart: Int, length: Int, side: Side) {
133       if (side.isLeft) {
134         builder1.put(onesideStart, twosideStart, length)
135       }
136       else {
137         builder2.put(onesideStart, twosideStart, length)
138       }
139       maxLength = Math.max(maxLength, onesideStart + length)
140       maxLength = Math.max(maxLength, twosideStart + length)
141     }
142
143     fun finish(): Test = Test(builder1.build(), builder2.build(), maxLength)
144   }
145
146   private class Test(val convertor1: LineNumberConvertor, val convertor2: LineNumberConvertor, var length: Int) {
147     fun change(onesideLine: Int, oldLength: Int, newLength: Int, side: Side) {
148       convertor1.handleMasterChange(onesideLine, onesideLine + oldLength, newLength - oldLength, side == Side.LEFT)
149       convertor2.handleMasterChange(onesideLine, onesideLine + oldLength, newLength - oldLength, side == Side.RIGHT)
150       length = Math.max(length, length + newLength - oldLength)
151     }
152
153     fun checkStrictSymmetrical() {
154       for (i in 0..length * 2) {
155         val value1 = convertor1.convertInv(i)
156         if (value1 != -1) assertEquals(i, convertor1.convert(value1))
157
158         val value2 = convertor2.convertInv(i)
159         if (value2 != -1) assertEquals(i, convertor2.convert(value2))
160
161         val value3 = convertor1.convert(i)
162         if (value3 != -1) assertEquals(i, convertor1.convertInv(value3))
163
164         val value4 = convertor2.convert(i)
165         if (value4 != -1) assertEquals(i, convertor2.convertInv(value4))
166       }
167     }
168
169     fun ensureMatchedCount(minimumMatched1: Int, minimumMatched2: Int) {
170       var counter1 = 0
171       var counter2 = 0
172       for (i in 0..length * 2) {
173         if (convertor1.convert(i) != -1) counter1++
174         if (convertor2.convert(i) != -1) counter2++
175       }
176       assertEquals(minimumMatched1, counter1)
177       assertEquals(minimumMatched2, counter2)
178     }
179
180     @Suppress("unused")
181     fun printMatchings() {
182       for (i in 0..length * 2 - 1) {
183         val value = convertor1.convert(i)
184         if (value != -1) println("L: $i - $value")
185       }
186
187       for (i in 0..length * 2 - 1) {
188         val value = convertor2.convert(i)
189         if (value != -1) println("R: $i - $value")
190       }
191     }
192   }
193 }