Browse Source

SONAR-2782 Fix detection of false-positive duplication in case of chain of cases

tags/2.12
Evgeny Mandrikov 12 years ago
parent
commit
438d36393d

+ 2
- 2
sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java View File

@@ -43,8 +43,8 @@ public final class JavaStatementBuilder {
.statement(from("else"))
.statement(from("for"), bridge("(", ")"))
.statement(from("while"), bridge("(", ")"))
.statement(from("case"), to(":"))
.statement(from("default"), to(":"))
.statement(from("case"), to(";", "{", "}"), forgetLastToken())
.statement(from("default"), to(";", "{", "}"), forgetLastToken())
.statement(to(";", "{", "}"), forgetLastToken())
.build();
}

+ 95
- 0
sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java View File

@@ -0,0 +1,95 @@
/*
* Sonar, open source software quality management tool.
* Copyright (C) 2008-2011 SonarSource
* mailto:contact AT sonarsource DOT com
*
* Sonar 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.
*
* Sonar 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 Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.duplications.java;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

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.index.CloneGroup;
import org.sonar.duplications.index.MemoryCloneIndex;
import org.sonar.duplications.statement.Statement;
import org.sonar.duplications.statement.StatementChunker;
import org.sonar.duplications.token.TokenChunker;

import com.google.common.base.Joiner;

public class JavaDuplicationsFunctionalTest {

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 List<CloneGroup> detect(String... lines) {
String sourceCode = Joiner.on('\n').join(lines);
MemoryCloneIndex index = new MemoryCloneIndex();
List<Statement> statements = statementChunker.chunk(tokenChunker.chunk(sourceCode));
List<Block> blocks = blockChunker.chunk("resourceId", statements);
for (Block block : blocks) {
index.insert(block);
}
return OriginalCloneDetectionAlgorithm.detect(index, blocks);
}

/**
* See SONAR-2837
*/
@Test
public void initializationOfMultidimensionalArray() {
List<CloneGroup> duplications = detect("int[][] idx = new int[][] { { 1, 2 }, { 3, 4 } };");
assertThat(duplications.size(), is(0));
}

/**
* See SONAR-2782
*/
@Test
public void chainOfCases() {
List<CloneGroup> duplications = detect(
"switch (a) {",
" case 'a': case 'b': case 'c':",
" doSomething();",
" case 'd': case 'e': case 'f':",
" doSomethingElse();",
"}");
assertThat(duplications.size(), is(0));
}

@Test
public void literalsNormalization() {
List<CloneGroup> duplications = detect(
"String s = \"abc\";",
"String s = \"def\";");
assertThat(duplications.size(), is(1));

duplications = detect(
"int i = 1;",
"int i = 2;");
assertThat(duplications.size(), is(1));
}

}

+ 26
- 10
sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java View File

@@ -127,17 +127,33 @@ public class JavaStatementBuilderTest {
"switch (month) {" +
" case 1 : monthString=\"January\"; break;" +
" case 2 : monthString=\"February\"; break;" +
" default: monthString=\"Invalid\";");
assertThat(statements.size(), is(9));
" default: monthString=\"Invalid\";" +
"}");
assertThat(statements.size(), is(6));
assertThat(statements.get(0).getValue(), is("switch(month)"));
assertThat(statements.get(1).getValue(), is("case$NUMBER:"));
assertThat(statements.get(2).getValue(), is("monthString=$CHARS"));
assertThat(statements.get(3).getValue(), is("break"));
assertThat(statements.get(4).getValue(), is("case$NUMBER:"));
assertThat(statements.get(5).getValue(), is("monthString=$CHARS"));
assertThat(statements.get(6).getValue(), is("break"));
assertThat(statements.get(7).getValue(), is("default:"));
assertThat(statements.get(8).getValue(), is("monthString=$CHARS"));
assertThat(statements.get(1).getValue(), is("case$NUMBER:monthString=$CHARS"));
assertThat(statements.get(2).getValue(), is("break"));
assertThat(statements.get(3).getValue(), is("case$NUMBER:monthString=$CHARS"));
assertThat(statements.get(4).getValue(), is("break"));
assertThat(statements.get(5).getValue(), is("default:monthString=$CHARS"));
}

/**
* See SONAR-2782
*/
@Test
public void shouldHandleNestedSwitch() {
List<Statement> statements = chunk("" +
"switch (a) {" +
" case 'a': case 'b': case 'c': something(); break;" +
" case 'd': case 'e': case 'f': somethingOther(); break;" +
"}");
assertThat(statements.size(), is(5));
assertThat(statements.get(0).getValue(), is("switch(a)"));
assertThat(statements.get(1).getValue(), is("case$CHARS:case$CHARS:case$CHARS:something()"));
assertThat(statements.get(2).getValue(), is("break"));
assertThat(statements.get(3).getValue(), is("case$CHARS:case$CHARS:case$CHARS:somethingOther()"));
assertThat(statements.get(4).getValue(), is("break"));
}

@Test

Loading…
Cancel
Save