diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-06-03 10:31:16 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2015-07-02 16:06:08 +0200 |
commit | bf4118d6a9ceb9ad24274cdc6537d4a607121815 (patch) | |
tree | 8f758ccb7a205da3eae96b05b74f79cade8ceae0 /sonar-core/src/test | |
parent | 2f948758eebec934beb54701792cf2d558319251 (diff) | |
download | sonarqube-bf4118d6a9ceb9ad24274cdc6537d4a607121815.tar.gz sonarqube-bf4118d6a9ceb9ad24274cdc6537d4a607121815.zip |
SONAR-6623 extract issue tracking algorithm from batch
Diffstat (limited to 'sonar-core/src/test')
19 files changed, 604 insertions, 135 deletions
diff --git a/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java index a84e1111836..136c5a262b5 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java @@ -21,7 +21,6 @@ package org.sonar.core.issue; import org.junit.Test; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/IssueChangeContextTest.java b/sonar-core/src/test/java/org/sonar/core/issue/IssueChangeContextTest.java index d6e304a309d..ed424565037 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/IssueChangeContextTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/IssueChangeContextTest.java @@ -20,7 +20,6 @@ package org.sonar.core.issue; import org.junit.Test; -import org.sonar.api.issue.internal.IssueChangeContext; import java.util.Date; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java b/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java index 8a4181f47b5..c3d927cbe3c 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java @@ -22,9 +22,6 @@ package org.sonar.core.issue; import org.junit.Before; import org.junit.Test; import org.sonar.api.issue.ActionPlan; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.issue.internal.FieldDiffs; -import org.sonar.api.issue.internal.IssueChangeContext; import org.sonar.api.user.User; import org.sonar.api.utils.Duration; import org.sonar.core.user.DefaultUser; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java index d9de4aa528f..411048b421e 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDaoTest.java @@ -23,8 +23,8 @@ import org.apache.ibatis.executor.result.DefaultResultHandler; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.sonar.api.issue.internal.DefaultIssueComment; -import org.sonar.api.issue.internal.FieldDiffs; +import org.sonar.core.issue.DefaultIssueComment; +import org.sonar.core.issue.FieldDiffs; import org.sonar.api.utils.DateUtils; import org.sonar.core.persistence.AbstractDaoTestCase; import org.sonar.core.persistence.DbSession; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDtoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDtoTest.java index 3b383c1c974..2d3ece83f18 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDtoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueChangeDtoTest.java @@ -20,8 +20,8 @@ package org.sonar.core.issue.db; import org.junit.Test; -import org.sonar.api.issue.internal.DefaultIssueComment; -import org.sonar.api.issue.internal.FieldDiffs; +import org.sonar.core.issue.DefaultIssueComment; +import org.sonar.core.issue.FieldDiffs; import org.sonar.api.utils.System2; import static org.assertj.core.api.Assertions.assertThat; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java index 7958aa26674..7738ca20486 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java @@ -47,41 +47,6 @@ public class IssueDaoTest extends AbstractDaoTestCase { } @Test - public void should_select_by_key() { - setupData("shared", "should_select_by_key"); - - IssueDto issue = dao.selectByKey("ABCDE"); - assertThat(issue.getKee()).isEqualTo("ABCDE"); - assertThat(issue.getId()).isEqualTo(100L); - assertThat(issue.getRuleId()).isEqualTo(500); - assertThat(issue.getSeverity()).isEqualTo("BLOCKER"); - assertThat(issue.isManualSeverity()).isFalse(); - assertThat(issue.getMessage()).isNull(); - assertThat(issue.getLine()).isEqualTo(200); - assertThat(issue.getEffortToFix()).isEqualTo(4.2); - assertThat(issue.getStatus()).isEqualTo("OPEN"); - assertThat(issue.getResolution()).isEqualTo("FIXED"); - assertThat(issue.getChecksum()).isEqualTo("XXX"); - assertThat(issue.getAuthorLogin()).isEqualTo("karadoc"); - assertThat(issue.getReporter()).isEqualTo("arthur"); - assertThat(issue.getAssignee()).isEqualTo("perceval"); - assertThat(issue.getIssueAttributes()).isEqualTo("JIRA=FOO-1234"); - assertThat(issue.getIssueCreationDate()).isNotNull(); - assertThat(issue.getIssueUpdateDate()).isNotNull(); - assertThat(issue.getIssueCloseDate()).isNotNull(); - assertThat(issue.getCreatedAt()).isNotNull(); - assertThat(issue.getUpdatedAt()).isNotNull(); - assertThat(issue.getRuleRepo()).isEqualTo("squid"); - assertThat(issue.getRule()).isEqualTo("AvoidCycle"); - assertThat(issue.getComponentUuid()).isEqualTo("CDEF"); - assertThat(issue.getComponentKey()).isEqualTo("Action.java"); - assertThat(issue.getModuleUuid()).isEqualTo("BCDE"); - assertThat(issue.getModuleUuidPath()).isEqualTo(".ABCD.BCDE."); - assertThat(issue.getProjectKey()).isEqualTo("struts"); // ABCD - assertThat(issue.getProjectUuid()).isEqualTo("ABCD"); // null - } - - @Test public void select_non_closed_issues_by_module() { setupData("shared", "should_select_non_closed_issues_by_module"); diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java index edac8a2dd84..0ee3ae23416 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueDtoTest.java @@ -24,7 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.core.issue.DefaultIssue; import org.sonar.api.utils.Duration; import org.sonar.core.rule.RuleDto; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java index 62e10059629..259f751c12e 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/IssueStorageTest.java @@ -22,9 +22,9 @@ package org.sonar.core.issue.db; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.issue.internal.DefaultIssueComment; -import org.sonar.api.issue.internal.IssueChangeContext; +import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.DefaultIssueComment; +import org.sonar.core.issue.IssueChangeContext; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/db/UpdateConflictResolverTest.java b/sonar-core/src/test/java/org/sonar/core/issue/db/UpdateConflictResolverTest.java index 2dc79d30b8d..9a4d5037901 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/db/UpdateConflictResolverTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/db/UpdateConflictResolverTest.java @@ -22,7 +22,7 @@ package org.sonar.core.issue.db; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.core.issue.DefaultIssue; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.utils.DateUtils; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java new file mode 100644 index 00000000000..f3646150846 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockHashSequenceTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.issue.tracking; + +import org.junit.Test; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class BlockHashSequenceTest { + + @Test + public void test() { + BlockHashSequence a = new BlockHashSequence(LineHashSequence.createForLines(asList("line0", "line1", "line2")), 1); + BlockHashSequence b = new BlockHashSequence(LineHashSequence.createForLines(asList("line0", "line1", "line2", "line3")), 1); + + assertThat(a.getBlockHashForLine(1)).isEqualTo(b.getBlockHashForLine(1)); + assertThat(a.getBlockHashForLine(2)).isEqualTo(b.getBlockHashForLine(2)); + assertThat(a.getBlockHashForLine(3)).isNotEqualTo(b.getBlockHashForLine(3)); + + BlockHashSequence c = new BlockHashSequence(LineHashSequence.createForLines(asList("line-1", "line0", "line1", "line2", "line3")), 1); + assertThat(a.getBlockHashForLine(1)).isNotEqualTo(c.getBlockHashForLine(2)); + assertThat(a.getBlockHashForLine(2)).isEqualTo(c.getBlockHashForLine(3)); + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java new file mode 100644 index 00000000000..d265e70d687 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/tracking/BlockRecognizerTest.java @@ -0,0 +1,56 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.issue.tracking; + +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BlockRecognizerTest { + + @Test + public void lengthOfMaximalBlock() { + /** + * - line 4 of first sequence is "d" + * - line 4 of second sequence is "d" + * - in each sequence, the 3 lines before and the line after are similar -> block size is 5 + */ + assertThat(compute(seq("abcde"), seq("abcde"), 4, 4)).isEqualTo(5); + + assertThat(compute(seq("abcde"), seq("abcd"), 4, 4)).isEqualTo(4); + assertThat(compute(seq("bcde"), seq("abcde"), 4, 4)).isEqualTo(0); + assertThat(compute(seq("bcde"), seq("abcde"), 3, 4)).isEqualTo(4); + } + + private int compute(LineHashSequence seqA, LineHashSequence seqB, int ai, int bi) { + return BlockRecognizer.lengthOfMaximalBlock(seqA, ai, seqB, bi); + } + + private static LineHashSequence seq(String text) { + List<String> hashes = new ArrayList<>(); + for (int i = 0; i < text.length(); i++) { + hashes.add("" + text.charAt(i)); + } + return new LineHashSequence(hashes); + } + +} diff --git a/sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java b/sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java new file mode 100644 index 00000000000..37391225a84 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/issue/tracking/TrackerTest.java @@ -0,0 +1,456 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.issue.tracking; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nullable; +import org.apache.commons.codec.digest.DigestUtils; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.rule.RuleKey; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class TrackerTest { + + public static final RuleKey RULE_SYSTEM_PRINT = RuleKey.of("java", "SystemPrint"); + public static final RuleKey RULE_UNUSED_LOCAL_VARIABLE = RuleKey.of("java", "UnusedLocalVariable"); + public static final RuleKey RULE_UNUSED_PRIVATE_METHOD = RuleKey.of("java", "UnusedPrivateMethod"); + public static final RuleKey RULE_NOT_DESIGNED_FOR_EXTENSION = RuleKey.of("java", "NotDesignedForExtension"); + @Rule + public ExpectedException thrown = ExpectedException.none(); + + Tracker<Issue, Issue> tracker = new Tracker<>(); + + /** + * Of course rule must match + */ + @Test + public void similar_issues_except_rule_do_not_match() { + FakeInput baseInput = new FakeInput("H1"); + baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + + FakeInput rawInput = new FakeInput("H1"); + Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isNull(); + } + + @Test + @Ignore + public void different_issues_do_not_match() { + FakeInput baseInput = new FakeInput("H1"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1"); + + FakeInput rawInput = new FakeInput("H2", "H3", "H4", "H5", "H6"); + Issue raw = rawInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "msg2"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isNull(); + assertThat(tracking.getUnmatchedBases()).containsOnly(base); + } + + @Test + public void line_hash_has_greater_priority_than_line() { + FakeInput baseInput = new FakeInput("H1", "H2", "H3"); + Issue base1 = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + Issue base2 = baseInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg"); + + FakeInput rawInput = new FakeInput("a", "b", "H1", "H2", "H3"); + Issue raw1 = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "msg"); + Issue raw2 = rawInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "msg"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw1)).isSameAs(base1); + assertThat(tracking.baseFor(raw2)).isSameAs(base2); + } + + /** + * SONAR-2928 + */ + @Test + public void no_lines_and_different_messages_match() { + FakeInput baseInput = new FakeInput("H1", "H2", "H3"); + Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1"); + + FakeInput rawInput = new FakeInput("H10", "H11", "H12"); + Issue raw = rawInput.createIssue(RULE_SYSTEM_PRINT, "msg2"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + @Test + public void similar_issues_except_message_match() { + FakeInput baseInput = new FakeInput("H1"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1"); + + FakeInput rawInput = new FakeInput("H1"); + Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg2"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + @Test + public void similar_issues_if_trimmed_messages_match() { + FakeInput baseInput = new FakeInput("H1"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, " message "); + + FakeInput rawInput = new FakeInput("H2"); + Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "message"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + /** + * Source code of this line was changed, but line and message still match + */ + @Test + public void similar_issues_except_line_hash_match() { + FakeInput baseInput = new FakeInput("H1"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + + FakeInput rawInput = new FakeInput("H2"); + Issue raw = rawInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + @Test + public void similar_issues_except_line_match() { + FakeInput baseInput = new FakeInput("H1", "H2"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + + FakeInput rawInput = new FakeInput("H2", "H1"); + Issue raw = rawInput.createIssueOnLine(2, RULE_SYSTEM_PRINT, "msg"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + /** + * SONAR-2812 + */ + @Test + public void only_same_line_hash_match_match() { + FakeInput baseInput = new FakeInput("H1", "H2"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg"); + + FakeInput rawInput = new FakeInput("H3", "H4", "H1"); + Issue raw = rawInput.createIssueOnLine(3, RULE_SYSTEM_PRINT, "other message"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isSameAs(base); + } + + @Test + public void do_not_fail_if_base_issue_without_line() throws Exception { + FakeInput baseInput = new FakeInput("H1", "H2"); + Issue base = baseInput.createIssueOnLine(1, RULE_SYSTEM_PRINT, "msg1"); + + FakeInput rawInput = new FakeInput("H3", "H4", "H5"); + Issue raw = rawInput.createIssue(RULE_UNUSED_LOCAL_VARIABLE, "msg2"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isNull(); + assertThat(tracking.getUnmatchedBases()).containsOnly(base); + } + + @Test + public void do_not_fail_if_raw_issue_without_line() throws Exception { + FakeInput baseInput = new FakeInput("H1", "H2"); + Issue base = baseInput.createIssue(RULE_SYSTEM_PRINT, "msg1"); + + FakeInput rawInput = new FakeInput("H3", "H4", "H5"); + Issue raw = rawInput.createIssueOnLine(1, RULE_UNUSED_LOCAL_VARIABLE, "msg2"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw)).isNull(); + assertThat(tracking.getUnmatchedBases()).containsOnly(base); + } + + @Test + public void fail_if_raw_line_does_not_exist() throws Exception { + FakeInput baseInput = new FakeInput(); + FakeInput rawInput = new FakeInput("H1").addIssue(new Issue(200, "H200", RULE_SYSTEM_PRINT, "msg")); + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Issue line is not valid"); + tracker.track(rawInput, baseInput); + } + + /** + * SONAR-3072 + */ + @Test + public void recognize_blocks_1() throws Exception { + FakeInput baseInput = FakeInput.createForSourceLines( + "package example1;", + "", + "public class Toto {", + "", + " public void doSomething() {", + " // doSomething", + " }", + "", + " public void doSomethingElse() {", + " // doSomethingElse", + " }", + "}" + ); + Issue base1 = baseInput.createIssueOnLine(7, RULE_SYSTEM_PRINT, "Indentation"); + Issue base2 = baseInput.createIssueOnLine(11, RULE_SYSTEM_PRINT, "Indentation"); + + FakeInput rawInput = FakeInput.createForSourceLines( + "package example1;", + "", + "public class Toto {", + "", + " public Toto(){}", + "", + " public void doSomethingNew() {", + " // doSomethingNew", + " }", + "", + " public void doSomethingElseNew() {", + " // doSomethingElseNew", + " }", + "", + " public void doSomething() {", + " // doSomething", + " }", + "", + " public void doSomethingElse() {", + " // doSomethingElse", + " }", + "}" + ); + Issue raw1 = rawInput.createIssueOnLine(9, RULE_SYSTEM_PRINT, "Indentation"); + Issue raw2 = rawInput.createIssueOnLine(13, RULE_SYSTEM_PRINT, "Indentation"); + Issue raw3 = rawInput.createIssueOnLine(17, RULE_SYSTEM_PRINT, "Indentation"); + Issue raw4 = rawInput.createIssueOnLine(21, RULE_SYSTEM_PRINT, "Indentation"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw1)).isNull(); + assertThat(tracking.baseFor(raw2)).isNull(); + assertThat(tracking.baseFor(raw3)).isSameAs(base1); + assertThat(tracking.baseFor(raw4)).isSameAs(base2); + assertThat(tracking.getUnmatchedBases()).isEmpty(); + } + + /** + * SONAR-3072 + */ + @Test + public void recognize_blocks_2() throws Exception { + FakeInput baseInput = FakeInput.createForSourceLines( + "package example2;", + "", + "public class Toto {", + " void method1() {", + " System.out.println(\"toto\");", + " }", + "}" + ); + Issue base1 = baseInput.createIssueOnLine(5, RULE_SYSTEM_PRINT, "SystemPrintln"); + + FakeInput rawInput = FakeInput.createForSourceLines( + "package example2;", + "", + "public class Toto {", + "", + " void method2() {", + " System.out.println(\"toto\");", + " }", + "", + " void method1() {", + " System.out.println(\"toto\");", + " }", + "", + " void method3() {", + " System.out.println(\"toto\");", + " }", + "}" + ); + Issue raw1 = rawInput.createIssueOnLine(6, RULE_SYSTEM_PRINT, "SystemPrintln"); + Issue raw2 = rawInput.createIssueOnLine(10, RULE_SYSTEM_PRINT, "SystemPrintln"); + Issue raw3 = rawInput.createIssueOnLine(14, RULE_SYSTEM_PRINT, "SystemPrintln"); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + assertThat(tracking.baseFor(raw1)).isNull(); + assertThat(tracking.baseFor(raw2)).isSameAs(base1); + assertThat(tracking.baseFor(raw3)).isNull(); + } + + @Test + public void recognize_blocks_3() throws Exception { + FakeInput baseInput = FakeInput.createForSourceLines( + "package sample;", + "", + "public class Sample {", + "\t", + "\tpublic Sample(int i) {", + "\t\tint j = i+1;", // UnusedLocalVariable + "\t}", + "", + "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension + "\t\treturn true;", + "\t}", + "", + "\tprivate String myMethod() {", // UnusedPrivateMethod + "\t\treturn \"hello\";", + "\t}", + "}" + ); + Issue base1 = baseInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'."); + Issue base2 = baseInput.createIssueOnLine(13, RULE_UNUSED_PRIVATE_METHOD, "Avoid unused private methods such as 'myMethod()'."); + Issue base3 = baseInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION, + "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty."); + + FakeInput rawInput = FakeInput.createForSourceLines( + "package sample;", + "", + "public class Sample {", + "", + "\tpublic Sample(int i) {", + "\t\tint j = i+1;", // UnusedLocalVariable is still there + "\t}", + "\t", + "\tpublic boolean avoidUtilityClass() {", // NotDesignedForExtension is still there + "\t\treturn true;", + "\t}", + "\t", + "\tprivate String myMethod() {", // issue UnusedPrivateMethod is fixed because it's called at line 18 + "\t\treturn \"hello\";", + "\t}", + "", + " public void newIssue() {", + " String msg = myMethod();", // new issue UnusedLocalVariable + " }", + "}" + ); + + Issue newRaw = rawInput.createIssueOnLine(18, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'msg'."); + Issue rawSameAsBase1 = rawInput.createIssueOnLine(6, RULE_UNUSED_LOCAL_VARIABLE, "Avoid unused local variables such as 'j'."); + Issue rawSameAsBase3 = rawInput.createIssueOnLine(9, RULE_NOT_DESIGNED_FOR_EXTENSION, + "Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty."); + + Tracking<Issue, Issue> tracking = tracker.track(rawInput, baseInput); + + assertThat(tracking.baseFor(newRaw)).isNull(); + assertThat(tracking.baseFor(rawSameAsBase1)).isSameAs(base1); + assertThat(tracking.baseFor(rawSameAsBase3)).isSameAs(base3); + assertThat(tracking.getUnmatchedBases()).containsOnly(base2); + } + + private static class Issue implements Trackable { + private final RuleKey ruleKey; + private final Integer line; + private final String message, lineHash; + + Issue(@Nullable Integer line, String lineHash, RuleKey ruleKey, String message) { + this.line = line; + this.lineHash = lineHash; + this.ruleKey = ruleKey; + this.message = message; + } + + @Override + public Integer getLine() { + return line; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String getLineHash() { + return lineHash; + } + + @Override + public RuleKey getRuleKey() { + return ruleKey; + } + } + + private static class FakeInput implements Input<Issue> { + private final List<Issue> issues = new ArrayList<>(); + private final List<String> lineHashes; + + public FakeInput(String... lineHashes) { + this.lineHashes = asList(lineHashes); + } + + static FakeInput createForSourceLines(String... lines) { + String[] hashes = new String[lines.length]; + for (int i = 0; i < lines.length; i++) { + hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", "")); + } + return new FakeInput(hashes); + } + + public Issue createIssueOnLine(int line, RuleKey ruleKey, String message) { + Issue issue = new Issue(line, lineHashes.get(line - 1), ruleKey, message); + issues.add(issue); + return issue; + } + + /** + * No line (line 0) + */ + public Issue createIssue(RuleKey ruleKey, String message) { + Issue issue = new Issue(null, "", ruleKey, message); + issues.add(issue); + return issue; + } + + public FakeInput addIssue(Issue issue) { + this.issues.add(issue); + return this; + } + + @Override + public LineHashSequence getLineHashSequence() { + return new LineHashSequence(lineHashes); + } + + @Override + public BlockHashSequence getBlockHashSequence() { + return new BlockHashSequence(getLineHashSequence(), 2); + } + + @Override + public Collection<Issue> getIssues() { + return issues; + } + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsEndOfLifeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsBeingClosedTest.java index 47ca6b3d526..04e6c29304e 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsEndOfLifeTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsBeingClosedTest.java @@ -20,24 +20,19 @@ package org.sonar.core.issue.workflow; import org.junit.Test; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.core.issue.DefaultIssue; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.core.issue.workflow.IsBeingClosed.INSTANCE; + +public class IsBeingClosedTest { -public class IsEndOfLifeTest { - DefaultIssue issue = new DefaultIssue(); @Test public void should_be_end_of_life() { - IsEndOfLife condition = new IsEndOfLife(true); - assertThat(condition.matches(issue.setEndOfLife(true))).isTrue(); - assertThat(condition.matches(issue.setEndOfLife(false))).isFalse(); + DefaultIssue issue = new DefaultIssue(); + assertThat(INSTANCE.matches(issue.setBeingClosed(true))).isTrue(); + assertThat(INSTANCE.matches(issue.setBeingClosed(false))).isFalse(); } - @Test - public void should_not_be_end_of_life() { - IsEndOfLife condition = new IsEndOfLife(false); - assertThat(condition.matches(issue.setEndOfLife(true))).isFalse(); - assertThat(condition.matches(issue.setEndOfLife(false))).isTrue(); - } } diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsManualTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsManualTest.java index 16a82274f04..78a581387c7 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsManualTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IsManualTest.java @@ -20,24 +20,19 @@ package org.sonar.core.issue.workflow; import org.junit.Test; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.api.rule.RuleKey; +import org.sonar.core.issue.DefaultIssue; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.core.issue.workflow.IsManual.INSTANCE; public class IsManualTest { - DefaultIssue issue = new DefaultIssue(); @Test public void should_match() { - IsManual condition = new IsManual(true); - assertThat(condition.matches(issue.setReporter("you"))).isTrue(); - assertThat(condition.matches(issue.setReporter(null))).isFalse(); + DefaultIssue issue = new DefaultIssue(); + assertThat(INSTANCE.matches(issue.setRuleKey(RuleKey.of(RuleKey.MANUAL_REPOSITORY_KEY, "R1")))).isTrue(); + assertThat(INSTANCE.matches(issue.setRuleKey(RuleKey.of("java", "R1")))).isFalse(); } - @Test - public void should_match_dead() { - IsManual condition = new IsManual(false); - assertThat(condition.matches(issue.setReporter("you"))).isFalse(); - assertThat(condition.matches(issue.setReporter(null))).isTrue(); - } } diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java index 8cc01a72189..ad5b9bef6e8 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/IssueWorkflowTest.java @@ -25,8 +25,8 @@ import org.apache.commons.lang.time.DateUtils; import org.junit.Test; import org.sonar.api.issue.DefaultTransitions; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.issue.internal.IssueChangeContext; +import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueChangeContext; import org.sonar.api.rule.RuleKey; import org.sonar.core.issue.IssueUpdater; @@ -106,7 +106,7 @@ public class IssueWorkflowTest { public void list_no_out_transition_from_status_closed() { workflow.start(); - DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CLOSED); + DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CLOSED).setRuleKey(RuleKey.of("java", "R1 ")); List<Transition> transitions = workflow.outTransitions(issue); assertThat(transitions).isEmpty(); } @@ -149,7 +149,7 @@ public class IssueWorkflowTest { .setResolution(Issue.RESOLUTION_FIXED) .setStatus(Issue.STATUS_RESOLVED) .setNew(false) - .setEndOfLife(true); + .setBeingClosed(true); Date now = new Date(); workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); @@ -167,7 +167,7 @@ public class IssueWorkflowTest { .setResolution(null) .setStatus(Issue.STATUS_OPEN) .setNew(false) - .setEndOfLife(true); + .setBeingClosed(true); Date now = new Date(); workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); @@ -185,7 +185,7 @@ public class IssueWorkflowTest { .setResolution(null) .setStatus(Issue.STATUS_REOPENED) .setNew(false) - .setEndOfLife(true); + .setBeingClosed(true); Date now = new Date(); workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); @@ -203,7 +203,7 @@ public class IssueWorkflowTest { .setResolution(null) .setStatus(Issue.STATUS_CONFIRMED) .setNew(false) - .setEndOfLife(true); + .setBeingClosed(true); Date now = new Date(); workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED); @@ -222,7 +222,7 @@ public class IssueWorkflowTest { .setResolution(Issue.RESOLUTION_FIXED) .setStatus("xxx") .setNew(false) - .setEndOfLife(true); + .setBeingClosed(true); try { workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(new Date())); fail(); @@ -346,7 +346,7 @@ public class IssueWorkflowTest { .setStatus(Issue.STATUS_OPEN) .setRuleKey(RuleKey.of("manual", "Performance")) .setReporter("simon") - .setEndOfLife(true) + .setBeingClosed(true) .setOnDisabledRule(true); workflow.start(); @@ -364,7 +364,7 @@ public class IssueWorkflowTest { .setStatus(Issue.STATUS_OPEN) .setRuleKey(RuleKey.of("manual", "Performance")) .setReporter("simon") - .setEndOfLife(true) + .setBeingClosed(true) .setOnDisabledRule(false); workflow.start(); diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetEndOfLifeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java index 014a8c2d087..84e46786292 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetEndOfLifeTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetClosedTest.java @@ -21,39 +21,39 @@ package org.sonar.core.issue.workflow; import org.junit.Test; import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.core.issue.DefaultIssue; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; +import static org.sonar.core.issue.workflow.SetClosed.INSTANCE; -public class SetEndOfLifeTest { +public class SetClosedTest { Function.Context context = mock(Function.Context.class); - SetEndOfLife function = new SetEndOfLife(); @Test public void should_resolve_as_fixed() { - Issue issue = new DefaultIssue().setEndOfLife(true).setOnDisabledRule(false); + Issue issue = new DefaultIssue().setBeingClosed(true).setOnDisabledRule(false); when(context.issue()).thenReturn(issue); - function.execute(context); + INSTANCE.execute(context); verify(context, times(1)).setResolution(Issue.RESOLUTION_FIXED); } @Test public void should_resolve_as_removed_when_rule_is_disabled() { - Issue issue = new DefaultIssue().setEndOfLife(true).setOnDisabledRule(true); + Issue issue = new DefaultIssue().setBeingClosed(true).setOnDisabledRule(true); when(context.issue()).thenReturn(issue); - function.execute(context); + INSTANCE.execute(context); verify(context, times(1)).setResolution(Issue.RESOLUTION_REMOVED); } @Test public void should_fail_if_issue_is_not_resolved() { - Issue issue = new DefaultIssue().setEndOfLife(false); + Issue issue = new DefaultIssue().setBeingClosed(false); when(context.issue()).thenReturn(issue); try { - function.execute(context); + INSTANCE.execute(context); fail(); } catch (IllegalStateException e) { assertThat(e.getMessage()).contains("Issue is still alive"); @@ -63,9 +63,9 @@ public class SetEndOfLifeTest { @Test public void line_number_must_be_unset() { - Issue issue = new DefaultIssue().setEndOfLife(true).setLine(10); + Issue issue = new DefaultIssue().setBeingClosed(true).setLine(10); when(context.issue()).thenReturn(issue); - function.execute(context); + INSTANCE.execute(context); verify(context).setLine(null); } } diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/TransitionTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/TransitionTest.java index 4c680c54ec1..eab956c6858 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/TransitionTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/TransitionTest.java @@ -21,7 +21,7 @@ package org.sonar.core.issue.workflow; import org.junit.Test; import org.sonar.api.issue.condition.Condition; -import org.sonar.api.issue.internal.DefaultIssue; +import org.sonar.core.issue.DefaultIssue; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; diff --git a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetAssigneeTest.java b/sonar-core/src/test/java/org/sonar/core/issue/workflow/UnsetAssigneeTest.java index ebadb4bccd9..3458baa77dd 100644 --- a/sonar-core/src/test/java/org/sonar/core/issue/workflow/SetAssigneeTest.java +++ b/sonar-core/src/test/java/org/sonar/core/issue/workflow/UnsetAssigneeTest.java @@ -21,25 +21,18 @@ package org.sonar.core.issue.workflow; import org.junit.Test; -import org.sonar.api.user.User; -import org.sonar.core.user.DefaultUser; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.sonar.core.issue.workflow.UnsetAssignee.INSTANCE; -public class SetAssigneeTest { - @Test - public void assign() { - User user = new DefaultUser().setLogin("eric").setName("eric"); - SetAssignee function = new SetAssignee(user); - Function.Context context = mock(Function.Context.class); - function.execute(context); - verify(context, times(1)).setAssignee(user); - } +public class UnsetAssigneeTest { @Test public void unassign() { Function.Context context = mock(Function.Context.class); - SetAssignee.UNASSIGN.execute(context); + INSTANCE.execute(context); verify(context, times(1)).setAssignee(null); } } diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml deleted file mode 100644 index 080269cef46..00000000000 --- a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_by_key.xml +++ /dev/null @@ -1,28 +0,0 @@ -<dataset> - - <issues - id="100" - kee="ABCDE" - component_uuid="CDEF" - project_uuid="ABCD" - rule_id="500" - severity="BLOCKER" - manual_severity="[false]" - message="[null]" - line="200" - effort_to_fix="4.2" - status="OPEN" - resolution="FIXED" - checksum="XXX" - reporter="arthur" - assignee="perceval" - author_login="karadoc" - issue_attributes="JIRA=FOO-1234" - issue_creation_date="1366063200000" - issue_update_date="1366063200000" - issue_close_date="1366063200000" - created_at="1400000000000" - updated_at="1400000000000" - /> - -</dataset> |