[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / platform / diff-impl / tests / com / intellij / diff / tools / fragmented / UnifiedFragmentBuilderAutoTest.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.DiffTestCase
19 import com.intellij.diff.comparison.ComparisonPolicy
20 import com.intellij.diff.util.DiffUtil
21 import com.intellij.diff.util.LineRange
22 import com.intellij.diff.util.Side
23 import com.intellij.openapi.editor.Document
24 import com.intellij.openapi.editor.impl.DocumentImpl
25 import com.intellij.openapi.progress.DumbProgressIndicator
26 import com.intellij.openapi.util.text.StringUtil
27
28 class UnifiedFragmentBuilderAutoTest : DiffTestCase() {
29   fun test() {
30     doTest(System.currentTimeMillis(), 30, 30)
31   }
32
33   fun doTest(seed: Long, runs: Int, maxLength: Int) {
34     doAutoTest(seed, runs) { debugData ->
35       debugData.put("MaxLength", maxLength)
36
37       val text1 = DocumentImpl(generateText(maxLength))
38       val text2 = DocumentImpl(generateText(maxLength))
39
40       debugData.put("Text1", textToReadableFormat(text1.charsSequence))
41       debugData.put("Text2", textToReadableFormat(text2.charsSequence))
42
43       for (side in Side.values()) {
44         for (comparisonPolicy in ComparisonPolicy.values()) {
45           debugData.put("Policy", comparisonPolicy)
46           debugData.put("Current side", side)
47           doTest(text1, text2, comparisonPolicy, side)
48         }
49       }
50     }
51   }
52
53   fun doTest(document1: Document, document2: Document, policy: ComparisonPolicy, masterSide: Side) {
54     val sequence1 = document1.charsSequence
55     val sequence2 = document2.charsSequence
56
57     val fragments = MANAGER.compareLinesInner(sequence1, sequence2, policy, DumbProgressIndicator.INSTANCE)
58
59     val builder = UnifiedFragmentBuilder(fragments, document1, document2, masterSide)
60     builder.exec()
61
62     val ignoreWhitespaces = policy !== ComparisonPolicy.DEFAULT
63     val text = builder.text
64     val blocks = builder.blocks
65     val convertor1 = builder.convertor1
66     val convertor2 = builder.convertor2
67     val changedLines = builder.changedLines
68     val ranges = builder.ranges
69
70     val document = DocumentImpl(text)
71
72     // both documents - before and after - should be subsequence of result text.
73     assertTrue(isSubsequence(text, sequence1, ignoreWhitespaces))
74     assertTrue(isSubsequence(text, sequence2, ignoreWhitespaces))
75
76     // all changes should be inside ChangedLines
77     for (fragment in fragments) {
78       val startLine1 = fragment.startLine1
79       val endLine1 = fragment.endLine1
80       val startLine2 = fragment.startLine2
81       val endLine2 = fragment.endLine2
82
83       for (i in startLine1 until endLine1) {
84         val targetLine = convertor1.convertInv(i)
85         assertTrue(targetLine != -1)
86         assertTrue(isLineChanged(targetLine, changedLines))
87       }
88       for (i in startLine2 until endLine2) {
89         val targetLine = convertor2.convertInv(i)
90         assertTrue(targetLine != -1)
91         assertTrue(isLineChanged(targetLine, changedLines))
92       }
93     }
94
95     // changed fragments and changed blocks should have same content
96     assertEquals(blocks.size, fragments.size)
97     for (i in fragments.indices) {
98       val fragment = fragments[i]
99       val block = blocks[i]
100
101       val fragment1 = sequence1.subSequence(fragment.startOffset1, fragment.endOffset1)
102       val fragment2 = sequence2.subSequence(fragment.startOffset2, fragment.endOffset2)
103
104       val block1 = DiffUtil.getLinesContent(document, block.range1.start, block.range1.end)
105       val block2 = DiffUtil.getLinesContent(document, block.range2.start, block.range2.end)
106
107       assertEqualsCharSequences(fragment1, block1, ignoreWhitespaces, true)
108       assertEqualsCharSequences(fragment2, block2, ignoreWhitespaces, true)
109     }
110
111     // ranges should have exact same content
112     for (range in ranges) {
113       val sideSequence = range.side.select(sequence1, sequence2)!!
114       val baseRange = text.subSequence(range.base.startOffset, range.base.endOffset)
115       val sideRange = sideSequence.subSequence(range.changed.startOffset, range.changed.endOffset)
116       assertTrue(StringUtil.equals(baseRange, sideRange))
117     }
118   }
119
120   private fun isSubsequence(text: CharSequence, sequence: CharSequence, ignoreWhitespaces: Boolean): Boolean {
121     var index1 = 0
122     var index2 = 0
123
124     while (index2 < sequence.length) {
125       val c2 = sequence[index2]
126       if (c2 == '\n' || (StringUtil.isWhiteSpace(c2) && ignoreWhitespaces)) {
127         index2++
128         continue
129       }
130
131       assertTrue(index1 < text.length)
132       val c1 = text[index1]
133       if (c1 == '\n' || (StringUtil.isWhiteSpace(c1) && ignoreWhitespaces)) {
134         index1++
135         continue
136       }
137
138       if (c1 == c2) {
139         index1++
140         index2++
141       }
142       else {
143         index1++
144       }
145     }
146
147     return true
148   }
149
150   private fun isLineChanged(line: Int, changedLines: List<LineRange>): Boolean {
151     for (changedLine in changedLines) {
152       if (changedLine.start <= line && changedLine.end > line) return true
153     }
154     return false
155   }
156 }