/* * 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 it.duplication; import com.google.common.collect.ObjectArrays; import com.sonar.orchestrator.Orchestrator; import it.Category4Suite; import java.util.Map; import org.apache.commons.io.IOUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.sonarqube.ws.client.issue.SearchWsRequest; import util.ItUtils; import util.issue.IssueRule; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; import static util.ItUtils.getMeasuresAsDoubleByMetricKey; import static util.ItUtils.runProjectAnalysis; import static util.ItUtils.setServerProperty; public class DuplicationsTest { static final String DUPLICATIONS = "file-duplications"; static final String DUPLICATIONS_WITH_EXCLUSIONS = "file-duplications-with-exclusions"; static final String WITHOUT_ENOUGH_TOKENS = "project_without_enough_tokens"; @ClassRule public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; @ClassRule public static final IssueRule issueRule = IssueRule.from(orchestrator); @BeforeClass public static void analyzeProjects() { orchestrator.resetData(); ItUtils.restoreProfile(orchestrator, DuplicationsTest.class.getResource("/duplication/xoo-duplication-profile.xml")); analyzeProject(DUPLICATIONS); analyzeProject(DUPLICATIONS_WITH_EXCLUSIONS, "sonar.cpd.exclusions", "**/File*"); // Set minimum tokens to a big value in order to not get duplications setServerProperty(orchestrator, "sonar.cpd.xoo.minimumTokens", "1000"); analyzeProject(WITHOUT_ENOUGH_TOKENS); } @AfterClass public static void resetProperties() throws Exception { setServerProperty(orchestrator, "sonar.cpd.xoo.minimumTokens", null); } @Test public void duplicated_lines_within_same_file() { verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_same_file/DuplicatedLinesInSameFile.xoo", 2, 30 * 2, // 2 blocks with 30 lines 1, 84.5); } @Test public void duplicated_same_lines_within_3_classes() { verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_same_lines_within_3_files/File1.xoo", 1, 33, 1, 78.6); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_same_lines_within_3_files/File2.xoo", 1, 31, 1, 75.6); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_same_lines_within_3_files/File3.xoo", 1, 31, 1, 70.5); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_same_lines_within_3_files", 3, 95, 3, 74.8); } @Test public void duplicated_lines_within_directory() { verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_dir/DuplicatedLinesInSameDirectory1.xoo", 1, 30, 1, 28.3); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_dir/DuplicatedLinesInSameDirectory2.xoo", 1, 30, 1, 41.7); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_dir", 2, 60, 2, 33.7); } @Test public void duplicated_lines_with_other_directory() { verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_with_other_dir1/DuplicatedLinesWithOtherDirectory.xoo", 1, 39, 1, 92.9); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_with_other_dir1", 1, 39, 1, 92.9); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_with_other_dir2/DuplicatedLinesWithOtherDirectory.xoo", 1, 39, 1, 92.9); verifyDuplicationMeasures(DUPLICATIONS + ":src/main/xoo/duplicated_lines_with_other_dir2", 1, 39, 1, 92.9); } @Test public void duplication_measures_on_project() { verifyDuplicationMeasures(DUPLICATIONS, 9, 293, 8, 63.7); } @Test public void project_without_enough_tokens_has_duplication() { verifyDuplicationMeasures(WITHOUT_ENOUGH_TOKENS, 0, 0, 0, 0d); } /** * SONAR-3108 */ @Test public void use_duplication_exclusions() { verifyDuplicationMeasures(DUPLICATIONS_WITH_EXCLUSIONS, 6, 198, 5, 43d); } @Test public void issues_on_duplicated_blocks_are_generated_on_each_file() throws Exception { assertThat(issueRule.search(new SearchWsRequest().setRules(singletonList("common-xoo:DuplicatedBlocks"))).getIssuesList()).hasSize(13); } @Test public void verify_sources_lines_ws_duplication_information() throws Exception { verifyWsResultOnDuplicateFile(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_same_file/DuplicatedLinesInSameFile.xoo", "api/sources/lines", "sources_lines_duplication-expected.json"); } @Test public void verify_duplications_show_ws() throws Exception { verifyWsResultOnDuplicateFile(DUPLICATIONS + ":src/main/xoo/duplicated_lines_within_same_file/DuplicatedLinesInSameFile.xoo", "api/duplications/show", "duplications_show-expected.json"); } private static Map<String, Double> getMeasures(String key) { return getMeasuresAsDoubleByMetricKey(orchestrator, key, "duplicated_lines", "duplicated_blocks", "duplicated_files", "duplicated_lines_density"); } private static void verifyDuplicationMeasures(String componentKey, int duplicatedBlocks, int duplicatedLines, int duplicatedFiles, double duplicatedLinesDensity) { Map<String, Double> measures = getMeasures(componentKey); assertThat(measures.get("duplicated_blocks").intValue()).isEqualTo(duplicatedBlocks); assertThat(measures.get("duplicated_lines").intValue()).isEqualTo(duplicatedLines); assertThat(measures.get("duplicated_files").intValue()).isEqualTo(duplicatedFiles); assertThat(measures.get("duplicated_lines_density")).isEqualTo(duplicatedLinesDensity); } private static void analyzeProject(String projectKey, String... additionalProperties) { orchestrator.getServer().provisionProject(projectKey, projectKey); orchestrator.getServer().associateProjectToQualityProfile(projectKey, "xoo", "xoo-duplication-profile"); runProjectAnalysis(orchestrator, "duplications/file-duplications", ObjectArrays.concat( new String[] { "sonar.projectKey", projectKey, "sonar.projectName", projectKey }, additionalProperties, String.class)); } private static void verifyWsResultOnDuplicateFile(String fileKey, String ws, String expectedFilePath) throws Exception { String duplication = orchestrator.getServer().adminWsClient().get(ws, "key", fileKey); assertEquals(IOUtils.toString(CrossProjectDuplicationsTest.class.getResourceAsStream("/duplication/DuplicationsTest/" + expectedFilePath), "UTF-8"), duplication, false); } }