From a96994a5842aa65cf73111d00d25c6e92b3be0a1 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 8 Dec 2011 09:49:04 +0400 Subject: Add couple of functional tests for CPD --- .../java/JavaDuplicationsFunctionalTest.java | 151 ++++++++++++++++++++- 1 file changed, 144 insertions(+), 7 deletions(-) (limited to 'sonar-duplications') diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java index c9a1c1b90c7..dd85d6adcb5 100644 --- a/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java +++ b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java @@ -22,13 +22,16 @@ package org.sonar.duplications.java; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import java.util.Collection; import java.util.List; import org.junit.Test; import org.sonar.duplications.block.Block; import org.sonar.duplications.block.BlockChunker; -import org.sonar.duplications.detector.original.OriginalCloneDetectionAlgorithm; +import org.sonar.duplications.detector.suffixtree.SuffixTreeCloneDetectionAlgorithm; import org.sonar.duplications.index.CloneGroup; +import org.sonar.duplications.index.CloneIndex; +import org.sonar.duplications.index.ClonePart; import org.sonar.duplications.index.MemoryCloneIndex; import org.sonar.duplications.statement.Statement; import org.sonar.duplications.statement.StatementChunker; @@ -36,23 +39,157 @@ import org.sonar.duplications.token.TokenChunker; import com.google.common.base.Joiner; +/** + * From A Survey on Software Clone Detection Research (2007 year): + * + */ public class JavaDuplicationsFunctionalTest { + @Test + public void type1() { + String fragment0 = source( + "if (a >= b) {", + " c = d + b; // Comment1", + " d = d + 1;}", + "else", + " c = d - a; // Comment2"); + String fragment1 = source( + "if (a>=b) {", + " // Comment1", + " c=d+b;", + " d=d+1;", + "} else // Comment2", + " c=d-a;"); + List duplications = detect2(fragment0, fragment1); + assertThat(duplications.size(), is(1)); + ClonePart part = duplications.get(0).getOriginPart(); + assertThat(part.getLineStart(), is(1)); + assertThat(part.getLineEnd(), is(5)); + } + + /** + * Supports only subset of Type 2. + * + * @see #type2 + * @see #literalsNormalization() + */ + @Test + public void type2_literals() { + String fragment0 = source( + "if (a >= b) {", + " c = b + 1; // Comment1", + " d = '1';}", + "else", + " c = d - a; // Comment2"); + String fragment1 = source( + "if (a >= b) {", + " c = b + 2; // Comment1", + " d = '2';}", + "else", + " c = d - a; // Comment2"); + List duplications = detect2(fragment0, fragment1); + assertThat(duplications.size(), is(1)); + ClonePart part = duplications.get(0).getOriginPart(); + assertThat(part.getLineStart(), is(1)); + assertThat(part.getLineEnd(), is(5)); + } + + @Test + public void type2() { + String fragment0 = source( + "if (a >= b) {", + " c = d + b; // Comment1", + " d = d + 1;}", + "else", + " c = d - a; // Comment2"); + String fragment1 = source( + "if (m >= n) {", + " // Comment3", + " y = x + n; // Comment1", + " x = x + 5;}", + "else", + " y = x - m; // Comment2"); + List duplications = detect2(fragment0, fragment1); + assertThat(duplications.size(), is(0)); + } + + /** + * Does not support Type 3, however able to detect inner parts. + */ + @Test + public void type3() { + String fragment0 = source( + "public int getSoLinger() throws SocketException {", + " Object o = impl.getOption( SocketOptions.SO_LINGER);", + " if (o instanceof Integer) {", + " return((Integer) o).intValue();", + " }", + " else return -1;", + "}"); + String fragment1 = source( + "public synchronized int getSoTimeout() throws SocketException {", + " Object o = impl.getOption( SocketOptions.SO_TIMEOUT);", + " if (o instanceof Integer) {", + " return((Integer) o).intValue();", + " }", + " else return -0;", + "}" + ); + List duplications = detect2(fragment0, fragment1); + assertThat(duplications.size(), is(1)); + ClonePart part = duplications.get(0).getOriginPart(); + assertThat(part.getLineStart(), is(3)); + assertThat(part.getLineEnd(), is(6)); + } + + private String source(String... lines) { + return Joiner.on('\n').join(lines); + } + + private static List detect2(String... fragments) { + MemoryCloneIndex index = new MemoryCloneIndex(); + for (int i = 0; i < fragments.length; i++) { + addToIndex(index, "fragment" + i, fragments[i]); + } + return detect(index, index.getByResourceId("fragment0")); + } + + private static void addToIndex(CloneIndex index, String resourceId, String sourceCode) { + List statements = STATEMENT_CHUNKER.chunk(TOKEN_CHUNKER.chunk(sourceCode)); + BlockChunker blockChunker = new BlockChunker(2); + List blocks = blockChunker.chunk(resourceId, statements); + for (Block block : blocks) { + index.insert(block); + } + } + + private static List detect(CloneIndex index, Collection blocks) { + return SuffixTreeCloneDetectionAlgorithm.detect(index, blocks); + } + private static final int BLOCK_SIZE = 1; - private TokenChunker tokenChunker = JavaTokenProducer.build(); - private StatementChunker statementChunker = JavaStatementBuilder.build(); - private BlockChunker blockChunker = new BlockChunker(BLOCK_SIZE); + private static TokenChunker TOKEN_CHUNKER = JavaTokenProducer.build(); + private static StatementChunker STATEMENT_CHUNKER = JavaStatementBuilder.build(); + private static BlockChunker BLOCK_CHUNKER = new BlockChunker(BLOCK_SIZE); private List detect(String... lines) { String sourceCode = Joiner.on('\n').join(lines); MemoryCloneIndex index = new MemoryCloneIndex(); - List statements = statementChunker.chunk(tokenChunker.chunk(sourceCode)); - List blocks = blockChunker.chunk("resourceId", statements); + List statements = STATEMENT_CHUNKER.chunk(TOKEN_CHUNKER.chunk(sourceCode)); + List blocks = BLOCK_CHUNKER.chunk("resourceId", statements); for (Block block : blocks) { index.insert(block); } - return OriginalCloneDetectionAlgorithm.detect(index, blocks); + return detect(index, blocks); } /** -- cgit v1.2.3