/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.duplications.detector.suffixtree;
import org.junit.Test;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.block.ByteArray;
import org.sonar.duplications.detector.DetectorTestCase;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.index.CloneIndex;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.sonar.duplications.detector.CloneGroupMatcher.hasCloneGroup;
public class SuffixTreeCloneDetectionAlgorithmTest extends DetectorTestCase {
/**
* Given: file without duplications
* Expected: {@link Collections#EMPTY_LIST} (no need to construct suffix-tree)
*/
@Test
public void noDuplications() {
CloneIndex index = createIndex();
Block[] fileBlocks = newBlocks("a", "1 2 3");
List<CloneGroup> result = detect(index, fileBlocks);
assertThat(result, sameInstance(Collections.EMPTY_LIST));
}
/**
* See SONAR-3060
* <p>
* In case when file contains a lot of duplicated blocks suffix-tree works better than original algorithm,
* which works more than 5 minutes for this example.
* </p><p>
* However should be noted that current implementation with suffix-tree also is not optimal,
* even if it works for this example couple of seconds,
* because duplications should be filtered in order to remove fully-covered.
* But such cases nearly never appear in real-world, so current implementation is acceptable for the moment.
* </p>
*/
@Test
public void huge() {
CloneIndex index = createIndex();
Block[] fileBlocks = new Block[5000];
for (int i = 0; i < 5000; i++) {
fileBlocks[i] = newBlock("x", new ByteArray("01"), i);
}
List<CloneGroup> result = detect(index, fileBlocks);
assertEquals(1, result.size());
}
/**
* Given:
* <pre>
* x: a 2 b 2 c 2 2 2
* </pre>
* Expected:
* <pre>
* x-x (2 2)
* x-x-x-x-x (2)
* <pre>
* TODO Godin: however would be better to receive only (2)
*/
@Test
public void myTest() {
CloneIndex index = createIndex();
Block[] fileBlocks = newBlocks("x", "a 2 b 2 c 2 2 2");
List<CloneGroup> result = detect(index, fileBlocks);
print(result);
assertEquals(2, result.size());
assertThat(result, hasCloneGroup(2,
newClonePart("x", 5, 2),
newClonePart("x", 6, 2)));
assertThat(result, hasCloneGroup(1,
newClonePart("x", 1, 1),
newClonePart("x", 3, 1),
newClonePart("x", 5, 1),
newClonePart("x", 6, 1),
newClonePart("x", 7, 1)));
}
/**
* This test and associated with it suffix-tree demonstrates that without filtering in {@link DuplicationsCollector#endOfGroup()}
* possible to construct {@link CloneGroup}, which is fully covered by another {@link CloneGroup}.
*
* Given:
* <pre>
* x: a 2 3 b 2 3 c 2 3 d 2 3 2 3 2 3
* </pre>
* Expected:
* <pre>
* x-x (2 3 2 3)
* x-x-x-x-x-x (2 3)
* <pre>
* TODO Godin: however would be better to receive only (2 3)
*/
@Test
public void myTest2() {
CloneIndex index = createIndex();
Block[] fileBlocks = newBlocks("x", "a 2 3 b 2 3 c 2 3 d 2 3 2 3 2 3");
List<CloneGroup> result = detect(index, fileBlocks);
print(result);
assertEquals(2, result.size());
assertThat(result, hasCloneGroup(4,
newClonePart("x", 10, 4),
newClonePart("x", 12, 4)));
assertThat(result, hasCloneGroup(2,
newClonePart("x", 1, 2),
newClonePart("x", 4, 2),
newClonePart("x", 7, 2),
newClonePart("x", 10, 2),
newClonePart("x", 12, 2),
newClonePart("x", 14, 2)));
}
/**
* This test and associated with it suffix-tree demonstrates that without check of origin in {@link Search}
* possible to construct {@link CloneGroup} with a wrong origin.
*
* Given:
* <pre>
* a: 1 2 3 4
* b: 4 3 2
* c: 4 3 1
* </pre>
* Expected:
* <pre>
* a-c (1)
* a-b (2)
* a-b-c (3)
* a-b-c (4)
* <pre>
*/
@Test
public void myTest3() {
CloneIndex index = createIndex(
newBlocks("b", "4 3 2"),
newBlocks("c", "4 3 1")
);
Block[] fileBlocks = newBlocks("a", "1 2 3 4");
List<CloneGroup> result = detect(index, fileBlocks);
print(result);
assertEquals(4, result.size());
assertThat(result, hasCloneGroup(1,
newClonePart("a", 0, 1),
newClonePart("c", 2, 1)));
assertThat(result, hasCloneGroup(1,
newClonePart("a", 1, 1),
newClonePart("b", 2, 1)));
assertThat(result, hasCloneGroup(1,
newClonePart("a", 2, 1),
newClonePart("b", 1, 1),
newClonePart("c", 1, 1)));
assertThat(result, hasCloneGroup(1,
newClonePart("a", 3, 1),
newClonePart("b", 0, 1),
newClonePart("c", 0, 1)));
}
@Override
protected List<CloneGroup> detect(CloneIndex index, Block[] fileBlocks) {
return SuffixTreeCloneDetectionAlgorithm.detect(index, Arrays.asList(fileBlocks));
}
}