aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorJulien HENRY <julien.henry@sonarsource.com>2015-01-21 11:22:44 +0100
committerJulien HENRY <julien.henry@sonarsource.com>2015-01-23 09:59:47 +0100
commit1340ee7da7a1688ebb059812504e117d041e0124 (patch)
tree171deefeac6057e876106131ac333bd4914d9253 /plugins
parent97ca9e16fc27e19f021558502fdce23fe9a77460 (diff)
downloadsonarqube-1340ee7da7a1688ebb059812504e117d041e0124.tar.gz
sonarqube-1340ee7da7a1688ebb059812504e117d041e0124.zip
SONAR-6012 Local issue tracking
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java10
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensor.java84
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesStack.java85
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueHandlers.java140
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java340
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java277
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingResult.java113
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/SourceHashHolder.java79
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/FileHashes.java77
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizer.java69
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/RollingFileHashes.java89
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/package-info.java23
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensorTest.java65
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesStackTest.java142
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueHandlersTest.java60
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java574
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java369
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/SourceHashHolderTest.java107
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizerTest.java49
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/RollingFileHashesTest.java43
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v1.txt12
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v2.txt22
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v1.txt7
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v2.txt16
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt16
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt20
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java7
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java7
28 files changed, 12 insertions, 2890 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
index 9040b071b1a..2187ca1cf85 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java
@@ -34,11 +34,6 @@ import org.sonar.plugins.core.dashboards.ProjectIssuesDashboard;
import org.sonar.plugins.core.dashboards.ProjectTimeMachineDashboard;
import org.sonar.plugins.core.issue.CountFalsePositivesDecorator;
import org.sonar.plugins.core.issue.CountUnresolvedIssuesDecorator;
-import org.sonar.plugins.core.issue.InitialOpenIssuesSensor;
-import org.sonar.plugins.core.issue.InitialOpenIssuesStack;
-import org.sonar.plugins.core.issue.IssueHandlers;
-import org.sonar.plugins.core.issue.IssueTracking;
-import org.sonar.plugins.core.issue.IssueTrackingDecorator;
import org.sonar.plugins.core.measurefilters.MyFavouritesFilter;
import org.sonar.plugins.core.measurefilters.ProjectFilter;
import org.sonar.plugins.core.notifications.alerts.NewAlerts;
@@ -325,13 +320,8 @@ public final class CorePlugin extends SonarPlugin {
DistributionAreaChart.class,
// issues
- IssueTrackingDecorator.class,
- IssueTracking.class,
- IssueHandlers.class,
CountUnresolvedIssuesDecorator.class,
CountFalsePositivesDecorator.class,
- InitialOpenIssuesSensor.class,
- InitialOpenIssuesStack.class,
HotspotMostViolatedRulesWidget.class,
MyUnresolvedIssuesWidget.class,
FalsePositiveIssuesWidget.class,
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensor.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensor.java
deleted file mode 100644
index 17f22757db8..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensor.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.apache.commons.lang.time.DateUtils;
-import org.apache.ibatis.session.ResultContext;
-import org.apache.ibatis.session.ResultHandler;
-import org.sonar.api.batch.Sensor;
-import org.sonar.api.batch.SensorContext;
-import org.sonar.api.resources.Project;
-import org.sonar.core.issue.db.IssueChangeDao;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDao;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * Load all the issues referenced during the previous scan.
- */
-public class InitialOpenIssuesSensor implements Sensor {
-
- private final InitialOpenIssuesStack initialOpenIssuesStack;
- private final IssueDao issueDao;
- private final IssueChangeDao issueChangeDao;
-
- public InitialOpenIssuesSensor(InitialOpenIssuesStack initialOpenIssuesStack, IssueDao issueDao, IssueChangeDao issueChangeDao) {
- this.initialOpenIssuesStack = initialOpenIssuesStack;
- this.issueDao = issueDao;
- this.issueChangeDao = issueChangeDao;
- }
-
- @Override
- public boolean shouldExecuteOnProject(Project project) {
- return true;
- }
-
- @Override
- public void analyse(Project project, SensorContext context) {
- // Adding one second is a hack for resolving conflicts with concurrent user
- // changes during issue persistence
- final Date now = DateUtils.addSeconds(DateUtils.truncate(new Date(), Calendar.MILLISECOND), 1);
-
- issueDao.selectNonClosedIssuesByModule(project.getId(), new ResultHandler() {
- @Override
- public void handleResult(ResultContext rc) {
- IssueDto dto = (IssueDto) rc.getResultObject();
- dto.setSelectedAt(now.getTime());
- initialOpenIssuesStack.addIssue(dto);
- }
- });
-
- issueChangeDao.selectChangelogOnNonClosedIssuesByModuleAndType(project.getId(), new ResultHandler() {
- @Override
- public void handleResult(ResultContext rc) {
- IssueChangeDto dto = (IssueChangeDto) rc.getResultObject();
- initialOpenIssuesStack.addChangelog(dto);
- }
- });
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesStack.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesStack.java
deleted file mode 100644
index 1d6f3592547..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/InitialOpenIssuesStack.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import java.util.Collections;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.batch.index.Cache;
-import org.sonar.batch.index.Caches;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-public class InitialOpenIssuesStack implements BatchExtension {
-
- private final Cache<IssueDto> issuesCache;
- private final Cache<ArrayList<IssueChangeDto>> issuesChangelogCache;
-
- public InitialOpenIssuesStack(Caches caches) {
- issuesCache = caches.createCache("last-open-issues");
- issuesChangelogCache = caches.createCache("issues-changelog");
- }
-
- public InitialOpenIssuesStack addIssue(IssueDto issueDto) {
- issuesCache.put(issueDto.getComponentKey(), issueDto.getKee(), issueDto);
- return this;
- }
-
- public List<IssueDto> selectAndRemoveIssues(String componentKey) {
- Iterable<IssueDto> issues = issuesCache.values(componentKey);
- List<IssueDto> result = newArrayList();
- for (IssueDto issue : issues) {
- result.add(issue);
- }
- issuesCache.clear(componentKey);
- return result;
- }
-
- public Iterable<IssueDto> selectAllIssues() {
- return issuesCache.values();
- }
-
- public InitialOpenIssuesStack addChangelog(IssueChangeDto issueChangeDto) {
- List<IssueChangeDto> changeDtos = issuesChangelogCache.get(issueChangeDto.getIssueKey());
- if (changeDtos == null) {
- changeDtos = newArrayList();
- }
- changeDtos.add(issueChangeDto);
- issuesChangelogCache.put(issueChangeDto.getIssueKey(), newArrayList(changeDtos));
- return this;
- }
-
- public List<IssueChangeDto> selectChangelog(String issueKey) {
- List<IssueChangeDto> changeDtos = issuesChangelogCache.get(issueKey);
- return changeDtos != null ? changeDtos : Collections.<IssueChangeDto>emptyList();
- }
-
- public void clear() {
- issuesCache.clear();
- issuesChangelogCache.clear();
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueHandlers.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueHandlers.java
deleted file mode 100644
index d416b57f061..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueHandlers.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.sonar.api.BatchExtension;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueHandler;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.user.User;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.user.DefaultUser;
-
-import javax.annotation.Nullable;
-
-public class IssueHandlers implements BatchExtension {
- private final IssueHandler[] handlers;
- private final DefaultContext context;
-
- public IssueHandlers(IssueUpdater updater, IssueHandler[] handlers) {
- this.handlers = handlers;
- this.context = new DefaultContext(updater);
- }
-
- public IssueHandlers(IssueUpdater updater) {
- this(updater, new IssueHandler[0]);
- }
-
- public void execute(DefaultIssue issue, IssueChangeContext changeContext) {
- context.reset(issue, changeContext);
- for (IssueHandler handler : handlers) {
- handler.onIssue(context);
- }
- }
-
- static class DefaultContext implements IssueHandler.Context {
- private final IssueUpdater updater;
- private DefaultIssue issue;
- private IssueChangeContext changeContext;
-
- private DefaultContext(IssueUpdater updater) {
- this.updater = updater;
- }
-
- private void reset(DefaultIssue i, IssueChangeContext changeContext) {
- this.issue = i;
- this.changeContext = changeContext;
- }
-
- @Override
- public Issue issue() {
- return issue;
- }
-
- @Override
- public boolean isNew() {
- return issue.isNew();
- }
-
- @Override
- public boolean isEndOfLife() {
- return issue.isEndOfLife();
- }
-
- @Override
- public IssueHandler.Context setLine(@Nullable Integer line) {
- updater.setLine(issue, line);
- return this;
- }
-
- @Override
- public IssueHandler.Context setMessage(@Nullable String s) {
- updater.setMessage(issue, s, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context setSeverity(String severity) {
- updater.setSeverity(issue, severity, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context setAuthorLogin(@Nullable String login) {
- updater.setAuthorLogin(issue, login, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context setEffortToFix(@Nullable Double d) {
- updater.setEffortToFix(issue, d, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context setAttribute(String key, @Nullable String value) {
- throw new UnsupportedOperationException("TODO");
- }
-
- @Override
- public IssueHandler.Context assign(@Nullable String assignee) {
- User user = null;
- if(assignee != null) {
- user = new DefaultUser().setLogin(assignee).setName(assignee);
- }
- updater.assign(issue, user, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context assign(@Nullable User user) {
- updater.assign(issue, user, changeContext);
- return this;
- }
-
- @Override
- public IssueHandler.Context addComment(String text) {
- updater.addComment(issue, text, changeContext);
- return this;
- }
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
deleted file mode 100644
index da4059eeb0d..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.plugins.core.issue.tracking.FileHashes;
-import org.sonar.plugins.core.issue.tracking.IssueTrackingBlocksRecognizer;
-import org.sonar.plugins.core.issue.tracking.RollingFileHashes;
-
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-
-public class IssueTracking implements BatchExtension {
-
- /**
- * @param sourceHashHolder Null when working on resource that is not a file (directory/project)
- */
- public IssueTrackingResult track(@Nullable SourceHashHolder sourceHashHolder, Collection<IssueDto> dbIssues, Collection<DefaultIssue> newIssues) {
- IssueTrackingResult result = new IssueTrackingResult();
-
- if (sourceHashHolder != null) {
- setChecksumOnNewIssues(newIssues, sourceHashHolder);
- }
-
- // Map new issues with old ones
- mapIssues(newIssues, dbIssues, sourceHashHolder, result);
- return result;
- }
-
- private void setChecksumOnNewIssues(Collection<DefaultIssue> issues, SourceHashHolder sourceHashHolder) {
- if (issues.isEmpty()) {
- return;
- }
- for (DefaultIssue issue : issues) {
- Integer line = issue.line();
- if (line != null) {
- issue.setChecksum(sourceHashHolder.getHashedSource().getHash(line));
- }
- }
- }
-
- @VisibleForTesting
- void mapIssues(Collection<DefaultIssue> newIssues, @Nullable Collection<IssueDto> lastIssues, @Nullable SourceHashHolder sourceHashHolder, IssueTrackingResult result) {
- boolean hasLastScan = false;
-
- if (lastIssues != null) {
- hasLastScan = true;
- mapLastIssues(newIssues, lastIssues, result);
- }
-
- // If each new issue matches an old one we can stop the matching mechanism
- if (result.matched().size() != newIssues.size()) {
- if (sourceHashHolder != null && hasLastScan) {
- FileHashes hashedReference = sourceHashHolder.getHashedReference();
- if (hashedReference != null) {
- mapNewissues(hashedReference, sourceHashHolder.getHashedSource(), newIssues, result);
- }
- }
- mapIssuesOnSameRule(newIssues, result);
- }
- }
-
- private void mapLastIssues(Collection<DefaultIssue> newIssues, Collection<IssueDto> lastIssues, IssueTrackingResult result) {
- for (IssueDto lastIssue : lastIssues) {
- result.addUnmatched(lastIssue);
- }
-
- // Match the key of the issue. (For manual issues)
- for (DefaultIssue newIssue : newIssues) {
- mapIssue(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).get(newIssue.key()), result);
- }
-
- // Try first to match issues on same rule with same line and with same checksum (but not necessarily with same message)
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result)) {
- mapIssue(
- newIssue,
- findLastIssueWithSameLineAndChecksum(newIssue, result),
- result);
- }
- }
- }
-
- private void mapNewissues(FileHashes hashedReference, FileHashes hashedSource, Collection<DefaultIssue> newIssues, IssueTrackingResult result) {
-
- IssueTrackingBlocksRecognizer rec = new IssueTrackingBlocksRecognizer(hashedReference, hashedSource);
-
- RollingFileHashes a = RollingFileHashes.create(hashedReference, 5);
- RollingFileHashes b = RollingFileHashes.create(hashedSource, 5);
-
- Multimap<Integer, DefaultIssue> newIssuesByLines = newIssuesByLines(newIssues, rec, result);
- Multimap<Integer, IssueDto> lastIssuesByLines = lastIssuesByLines(result.unmatched(), rec);
-
- Map<Integer, HashOccurrence> map = Maps.newHashMap();
-
- for (Integer line : lastIssuesByLines.keySet()) {
- int hash = a.getHash(line);
- HashOccurrence hashOccurrence = map.get(hash);
- if (hashOccurrence == null) {
- // first occurrence in A
- hashOccurrence = new HashOccurrence();
- hashOccurrence.lineA = line;
- hashOccurrence.countA = 1;
- map.put(hash, hashOccurrence);
- } else {
- hashOccurrence.countA++;
- }
- }
-
- for (Integer line : newIssuesByLines.keySet()) {
- int hash = b.getHash(line);
- HashOccurrence hashOccurrence = map.get(hash);
- if (hashOccurrence != null) {
- hashOccurrence.lineB = line;
- hashOccurrence.countB++;
- }
- }
-
- for (HashOccurrence hashOccurrence : map.values()) {
- if (hashOccurrence.countA == 1 && hashOccurrence.countB == 1) {
- // Guaranteed that lineA has been moved to lineB, so we can map all issues on lineA to all issues on lineB
- map(newIssuesByLines.get(hashOccurrence.lineB), lastIssuesByLines.get(hashOccurrence.lineA), result);
- lastIssuesByLines.removeAll(hashOccurrence.lineA);
- newIssuesByLines.removeAll(hashOccurrence.lineB);
- }
- }
-
- // Check if remaining number of lines exceeds threshold
- if (lastIssuesByLines.keySet().size() * newIssuesByLines.keySet().size() < 250000) {
- List<LinePair> possibleLinePairs = Lists.newArrayList();
- for (Integer oldLine : lastIssuesByLines.keySet()) {
- for (Integer newLine : newIssuesByLines.keySet()) {
- int weight = rec.computeLengthOfMaximalBlock(oldLine, newLine);
- possibleLinePairs.add(new LinePair(oldLine, newLine, weight));
- }
- }
- Collections.sort(possibleLinePairs, LINE_PAIR_COMPARATOR);
- for (LinePair linePair : possibleLinePairs) {
- // High probability that lineA has been moved to lineB, so we can map all Issues on lineA to all Issues on lineB
- map(newIssuesByLines.get(linePair.lineB), lastIssuesByLines.get(linePair.lineA), result);
- }
- }
- }
-
- private void mapIssuesOnSameRule(Collection<DefaultIssue> newIssues, IssueTrackingResult result) {
- // Try then to match issues on same rule with same message and with same checksum
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result)) {
- mapIssue(
- newIssue,
- findLastIssueWithSameChecksumAndMessage(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()),
- result);
- }
- }
-
- // Try then to match issues on same rule with same line and with same message
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result)) {
- mapIssue(
- newIssue,
- findLastIssueWithSameLineAndMessage(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()),
- result);
- }
- }
-
- // Last check: match issue if same rule and same checksum but different line and different message
- // See SONAR-2812
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result)) {
- mapIssue(
- newIssue,
- findLastIssueWithSameChecksum(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()),
- result);
- }
- }
- }
-
- private void map(Collection<DefaultIssue> newIssues, Collection<IssueDto> lastIssues, IssueTrackingResult result) {
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result)) {
- for (IssueDto pastIssue : lastIssues) {
- if (isNotAlreadyMapped(pastIssue, result) && Objects.equal(newIssue.ruleKey(), RuleKey.of(pastIssue.getRuleRepo(), pastIssue.getRule()))) {
- mapIssue(newIssue, pastIssue, result);
- break;
- }
- }
- }
- }
- }
-
- private Multimap<Integer, DefaultIssue> newIssuesByLines(Collection<DefaultIssue> newIssues, IssueTrackingBlocksRecognizer rec, IssueTrackingResult result) {
- Multimap<Integer, DefaultIssue> newIssuesByLines = LinkedHashMultimap.create();
- for (DefaultIssue newIssue : newIssues) {
- if (isNotAlreadyMapped(newIssue, result) && rec.isValidLineInSource(newIssue.line())) {
- newIssuesByLines.put(newIssue.line(), newIssue);
- }
- }
- return newIssuesByLines;
- }
-
- private Multimap<Integer, IssueDto> lastIssuesByLines(Collection<IssueDto> lastIssues, IssueTrackingBlocksRecognizer rec) {
- Multimap<Integer, IssueDto> lastIssuesByLines = LinkedHashMultimap.create();
- for (IssueDto pastIssue : lastIssues) {
- if (rec.isValidLineInReference(pastIssue.getLine())) {
- lastIssuesByLines.put(pastIssue.getLine(), pastIssue);
- }
- }
- return lastIssuesByLines;
- }
-
- private IssueDto findLastIssueWithSameChecksum(DefaultIssue newIssue, Collection<IssueDto> lastIssues) {
- for (IssueDto pastIssue : lastIssues) {
- if (isSameChecksum(newIssue, pastIssue)) {
- return pastIssue;
- }
- }
- return null;
- }
-
- private IssueDto findLastIssueWithSameLineAndMessage(DefaultIssue newIssue, Collection<IssueDto> lastIssues) {
- for (IssueDto pastIssue : lastIssues) {
- if (isSameLine(newIssue, pastIssue) && isSameMessage(newIssue, pastIssue)) {
- return pastIssue;
- }
- }
- return null;
- }
-
- private IssueDto findLastIssueWithSameChecksumAndMessage(DefaultIssue newIssue, Collection<IssueDto> lastIssues) {
- for (IssueDto pastIssue : lastIssues) {
- if (isSameChecksum(newIssue, pastIssue) && isSameMessage(newIssue, pastIssue)) {
- return pastIssue;
- }
- }
- return null;
- }
-
- private IssueDto findLastIssueWithSameLineAndChecksum(DefaultIssue newIssue, IssueTrackingResult result) {
- Collection<IssueDto> sameRuleAndSameLineAndSameChecksum = result.unmatchedForRuleAndForLineAndForChecksum(newIssue.ruleKey(), newIssue.line(), newIssue.checksum());
- if (!sameRuleAndSameLineAndSameChecksum.isEmpty()) {
- return sameRuleAndSameLineAndSameChecksum.iterator().next();
- }
- return null;
- }
-
- private boolean isNotAlreadyMapped(IssueDto pastIssue, IssueTrackingResult result) {
- return result.unmatched().contains(pastIssue);
- }
-
- private boolean isNotAlreadyMapped(DefaultIssue newIssue, IssueTrackingResult result) {
- return !result.isMatched(newIssue);
- }
-
- private boolean isSameChecksum(DefaultIssue newIssue, IssueDto pastIssue) {
- return Objects.equal(pastIssue.getChecksum(), newIssue.checksum());
- }
-
- private boolean isSameLine(DefaultIssue newIssue, IssueDto pastIssue) {
- return Objects.equal(pastIssue.getLine(), newIssue.line());
- }
-
- private boolean isSameMessage(DefaultIssue newIssue, IssueDto pastIssue) {
- return Objects.equal(newIssue.message(), pastIssue.getMessage());
- }
-
- private void mapIssue(DefaultIssue issue, @Nullable IssueDto ref, IssueTrackingResult result) {
- if (ref != null) {
- result.setMatch(issue, ref);
- }
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-
- private static class LinePair {
- int lineA;
- int lineB;
- int weight;
-
- public LinePair(int lineA, int lineB, int weight) {
- this.lineA = lineA;
- this.lineB = lineB;
- this.weight = weight;
- }
- }
-
- private static class HashOccurrence {
- int lineA;
- int lineB;
- int countA;
- int countB;
- }
-
- private static final Comparator<LinePair> LINE_PAIR_COMPARATOR = new Comparator<LinePair>() {
- @Override
- public int compare(LinePair o1, LinePair o2) {
- int weightDiff = o2.weight - o1.weight;
- if (weightDiff != 0) {
- return weightDiff;
- } else {
- return Math.abs(o1.lineA - o1.lineB) - Math.abs(o2.lineA - o2.lineB);
- }
- }
- };
-
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
deleted file mode 100644
index 3d2bfc48e9d..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issuable;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.rules.ActiveRule;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.KeyValueFormat;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.LastLineHashes;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.workflow.IssueWorkflow;
-
-import java.util.Collection;
-
-@DependsUpon(DecoratorBarriers.ISSUES_ADDED)
-@DependedUpon(DecoratorBarriers.ISSUES_TRACKED)
-public class IssueTrackingDecorator implements Decorator {
-
- private static final Logger LOG = LoggerFactory.getLogger(IssueTrackingDecorator.class);
-
- private final IssueCache issueCache;
- private final InitialOpenIssuesStack initialOpenIssues;
- private final IssueTracking tracking;
- private final LastLineHashes lastLineHashes;
- private final IssueHandlers handlers;
- private final IssueWorkflow workflow;
- private final IssueUpdater updater;
- private final IssueChangeContext changeContext;
- private final ResourcePerspectives perspectives;
- private final RulesProfile rulesProfile;
- private final RuleFinder ruleFinder;
- private final InputPathCache inputPathCache;
- private final Project project;
-
- public IssueTrackingDecorator(IssueCache issueCache, InitialOpenIssuesStack initialOpenIssues, IssueTracking tracking,
- LastLineHashes lastLineHashes,
- IssueHandlers handlers, IssueWorkflow workflow,
- IssueUpdater updater,
- Project project,
- ResourcePerspectives perspectives,
- RulesProfile rulesProfile,
- RuleFinder ruleFinder, InputPathCache inputPathCache) {
- this.issueCache = issueCache;
- this.initialOpenIssues = initialOpenIssues;
- this.tracking = tracking;
- this.lastLineHashes = lastLineHashes;
- this.handlers = handlers;
- this.workflow = workflow;
- this.updater = updater;
- this.project = project;
- this.inputPathCache = inputPathCache;
- this.changeContext = IssueChangeContext.createScan(project.getAnalysisDate());
- this.perspectives = perspectives;
- this.rulesProfile = rulesProfile;
- this.ruleFinder = ruleFinder;
- }
-
- @Override
- public boolean shouldExecuteOnProject(Project project) {
- return true;
- }
-
- @Override
- public void decorate(Resource resource, DecoratorContext context) {
- Issuable issuable = perspectives.as(Issuable.class, resource);
- if (issuable != null) {
- doDecorate(resource);
- }
- }
-
- @VisibleForTesting
- void doDecorate(Resource resource) {
- Collection<DefaultIssue> issues = Lists.newArrayList();
- for (Issue issue : issueCache.byComponent(resource.getEffectiveKey())) {
- issues.add((DefaultIssue) issue);
- }
- issueCache.clear(resource.getEffectiveKey());
- // issues = all the issues created by rule engines during this module scan and not excluded by filters
-
- // all the issues that are not closed in db before starting this module scan, including manual issues
- Collection<IssueDto> dbOpenIssues = initialOpenIssues.selectAndRemoveIssues(resource.getEffectiveKey());
-
- SourceHashHolder sourceHashHolder = null;
- if (ResourceUtils.isFile(resource)) {
- File sonarFile = (File) resource;
- InputFile file = inputPathCache.getFile(project.getEffectiveKey(), sonarFile.getPath());
- if (file == null) {
- throw new IllegalStateException("Resource " + resource + " was not found in InputPath cache");
- }
- sourceHashHolder = new SourceHashHolder((DefaultInputFile) file, lastLineHashes);
- }
-
- IssueTrackingResult trackingResult = tracking.track(sourceHashHolder, dbOpenIssues, issues);
-
- // unmatched = issues that have been resolved + issues on disabled/removed rules + manual issues
- addUnmatched(trackingResult.unmatched(), sourceHashHolder, issues);
-
- mergeMatched(trackingResult);
-
- if (ResourceUtils.isProject(resource)) {
- // issues that relate to deleted components
- addIssuesOnDeletedComponents(issues);
- }
-
- for (DefaultIssue issue : issues) {
- workflow.doAutomaticTransition(issue, changeContext);
- handlers.execute(issue, changeContext);
- issueCache.put(issue);
- }
- }
-
- @VisibleForTesting
- protected void mergeMatched(IssueTrackingResult result) {
- for (DefaultIssue issue : result.matched()) {
- IssueDto ref = result.matching(issue);
-
- // invariant fields
- issue.setKey(ref.getKee());
- issue.setCreationDate(ref.getIssueCreationDate());
- issue.setUpdateDate(ref.getIssueUpdateDate());
- issue.setCloseDate(ref.getIssueCloseDate());
-
- // non-persisted fields
- issue.setNew(false);
- issue.setEndOfLife(false);
- issue.setOnDisabledRule(false);
- issue.setSelectedAt(ref.getSelectedAt());
-
- // fields to update with old values
- issue.setActionPlanKey(ref.getActionPlanKey());
- issue.setResolution(ref.getResolution());
- issue.setStatus(ref.getStatus());
- issue.setAssignee(ref.getAssignee());
- issue.setAuthorLogin(ref.getAuthorLogin());
- issue.setTags(ref.getTags());
-
- if (ref.getIssueAttributes() != null) {
- issue.setAttributes(KeyValueFormat.parse(ref.getIssueAttributes()));
- }
-
- // populate existing changelog
- Collection<IssueChangeDto> issueChangeDtos = initialOpenIssues.selectChangelog(issue.key());
- for (IssueChangeDto issueChangeDto : issueChangeDtos) {
- issue.addChange(issueChangeDto.toFieldDiffs());
- }
-
- // fields to update with current values
- if (ref.isManualSeverity()) {
- issue.setManualSeverity(true);
- issue.setSeverity(ref.getSeverity());
- } else {
- updater.setPastSeverity(issue, ref.getSeverity(), changeContext);
- }
- updater.setPastLine(issue, ref.getLine());
- updater.setPastMessage(issue, ref.getMessage(), changeContext);
- updater.setPastEffortToFix(issue, ref.getEffortToFix(), changeContext);
- Long debtInMinutes = ref.getDebt();
- Duration previousTechnicalDebt = debtInMinutes != null ? Duration.create(debtInMinutes) : null;
- updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext);
- updater.setPastProject(issue, ref.getProjectKey(), changeContext);
- }
- }
-
- private void addUnmatched(Collection<IssueDto> unmatchedIssues, SourceHashHolder sourceHashHolder, Collection<DefaultIssue> issues) {
- for (IssueDto unmatchedDto : unmatchedIssues) {
- DefaultIssue unmatched = unmatchedDto.toDefaultIssue();
- if (StringUtils.isNotBlank(unmatchedDto.getReporter()) && !Issue.STATUS_CLOSED.equals(unmatchedDto.getStatus())) {
- relocateManualIssue(unmatched, unmatchedDto, sourceHashHolder);
- }
- updateUnmatchedIssue(unmatched, false /* manual issues can be kept open */);
- issues.add(unmatched);
- }
- }
-
- private void addIssuesOnDeletedComponents(Collection<DefaultIssue> issues) {
- for (IssueDto deadDto : initialOpenIssues.selectAllIssues()) {
- DefaultIssue dead = deadDto.toDefaultIssue();
- updateUnmatchedIssue(dead, true);
- issues.add(dead);
- }
- initialOpenIssues.clear();
- }
-
- private void updateUnmatchedIssue(DefaultIssue issue, boolean forceEndOfLife) {
- issue.setNew(false);
-
- boolean manualIssue = !Strings.isNullOrEmpty(issue.reporter());
- Rule rule = ruleFinder.findByKey(issue.ruleKey());
- if (manualIssue) {
- // Manual rules are not declared in Quality profiles, so no need to check ActiveRule
- boolean isRemovedRule = rule == null || Rule.STATUS_REMOVED.equals(rule.getStatus());
- issue.setEndOfLife(forceEndOfLife || isRemovedRule);
- issue.setOnDisabledRule(isRemovedRule);
- } else {
- ActiveRule activeRule = rulesProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule());
- issue.setEndOfLife(true);
- issue.setOnDisabledRule(activeRule == null || rule == null || Rule.STATUS_REMOVED.equals(rule.getStatus()));
- }
- }
-
- private void relocateManualIssue(DefaultIssue newIssue, IssueDto oldIssue, SourceHashHolder sourceHashHolder) {
- LOG.debug("Trying to relocate manual issue {}", oldIssue.getKee());
-
- Integer previousLine = oldIssue.getLine();
- if (previousLine == null) {
- LOG.debug("Cannot relocate issue at resource level");
- return;
- }
-
- Collection<Integer> newLinesWithSameHash = sourceHashHolder.getNewLinesMatching(previousLine);
- LOG.debug("Found the following lines with same hash: {}", newLinesWithSameHash);
- if (newLinesWithSameHash.isEmpty()) {
- if (previousLine > sourceHashHolder.getHashedSource().length()) {
- LOG.debug("Old issue line {} is out of new source, closing and removing line number", previousLine);
- newIssue.setLine(null);
- updater.setStatus(newIssue, Issue.STATUS_CLOSED, changeContext);
- updater.setResolution(newIssue, Issue.RESOLUTION_REMOVED, changeContext);
- updater.setPastLine(newIssue, previousLine);
- updater.setPastMessage(newIssue, oldIssue.getMessage(), changeContext);
- updater.setPastEffortToFix(newIssue, oldIssue.getEffortToFix(), changeContext);
- }
- } else if (newLinesWithSameHash.size() == 1) {
- Integer newLine = newLinesWithSameHash.iterator().next();
- LOG.debug("Relocating issue to line {}", newLine);
-
- newIssue.setLine(newLine);
- updater.setPastLine(newIssue, previousLine);
- updater.setPastMessage(newIssue, oldIssue.getMessage(), changeContext);
- updater.setPastEffortToFix(newIssue, oldIssue.getEffortToFix(), changeContext);
- }
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingResult.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingResult.java
deleted file mode 100644
index f63f94f8115..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingResult.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.core.issue.db.IssueDto;
-
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-class IssueTrackingResult {
- private final Map<String, IssueDto> unmatchedByKey = new HashMap<String, IssueDto>();
- private final Map<RuleKey, Map<String, IssueDto>> unmatchedByRuleAndKey = new HashMap<RuleKey, Map<String, IssueDto>>();
- private final Map<RuleKey, Map<Integer, Multimap<String, IssueDto>>> unmatchedByRuleAndLineAndChecksum =
- new HashMap<RuleKey, Map<Integer, Multimap<String, IssueDto>>>();
- private final Map<DefaultIssue, IssueDto> matched = Maps.newIdentityHashMap();
-
- Collection<IssueDto> unmatched() {
- return unmatchedByKey.values();
- }
-
- Map<String, IssueDto> unmatchedByKeyForRule(RuleKey ruleKey) {
- return unmatchedByRuleAndKey.containsKey(ruleKey) ? unmatchedByRuleAndKey.get(ruleKey) : Collections.<String, IssueDto>emptyMap();
- }
-
- Collection<IssueDto> unmatchedForRuleAndForLineAndForChecksum(RuleKey ruleKey, @Nullable Integer line, @Nullable String checksum) {
- if (!unmatchedByRuleAndLineAndChecksum.containsKey(ruleKey)) {
- return Collections.emptyList();
- }
- Map<Integer, Multimap<String, IssueDto>> unmatchedForRule = unmatchedByRuleAndLineAndChecksum.get(ruleKey);
- Integer lineNotNull = line != null ? line : 0;
- if (!unmatchedForRule.containsKey(lineNotNull)) {
- return Collections.emptyList();
- }
- Multimap<String, IssueDto> unmatchedForRuleAndLine = unmatchedForRule.get(lineNotNull);
- String checksumNotNull = StringUtils.defaultString(checksum, "");
- if (!unmatchedForRuleAndLine.containsKey(checksumNotNull)) {
- return Collections.emptyList();
- }
- return unmatchedForRuleAndLine.get(checksumNotNull);
- }
-
- Collection<DefaultIssue> matched() {
- return matched.keySet();
- }
-
- boolean isMatched(DefaultIssue issue) {
- return matched.containsKey(issue);
- }
-
- IssueDto matching(DefaultIssue issue) {
- return matched.get(issue);
- }
-
- void addUnmatched(IssueDto i) {
- unmatchedByKey.put(i.getKee(), i);
- RuleKey ruleKey = RuleKey.of(i.getRuleRepo(), i.getRule());
- if (!unmatchedByRuleAndKey.containsKey(ruleKey)) {
- unmatchedByRuleAndKey.put(ruleKey, new HashMap<String, IssueDto>());
- unmatchedByRuleAndLineAndChecksum.put(ruleKey, new HashMap<Integer, Multimap<String, IssueDto>>());
- }
- unmatchedByRuleAndKey.get(ruleKey).put(i.getKee(), i);
- Map<Integer, Multimap<String, IssueDto>> unmatchedForRule = unmatchedByRuleAndLineAndChecksum.get(ruleKey);
- Integer lineNotNull = lineNotNull(i);
- if (!unmatchedForRule.containsKey(lineNotNull)) {
- unmatchedForRule.put(lineNotNull, HashMultimap.<String, IssueDto>create());
- }
- Multimap<String, IssueDto> unmatchedForRuleAndLine = unmatchedForRule.get(lineNotNull);
- String checksumNotNull = StringUtils.defaultString(i.getChecksum(), "");
- unmatchedForRuleAndLine.put(checksumNotNull, i);
- }
-
- private Integer lineNotNull(IssueDto i) {
- Integer line = i.getLine();
- return line != null ? line : 0;
- }
-
- void setMatch(DefaultIssue issue, IssueDto matching) {
- matched.put(issue, matching);
- RuleKey ruleKey = RuleKey.of(matching.getRuleRepo(), matching.getRule());
- unmatchedByRuleAndKey.get(ruleKey).remove(matching.getKee());
- unmatchedByKey.remove(matching.getKee());
- Integer lineNotNull = lineNotNull(matching);
- String checksumNotNull = StringUtils.defaultString(matching.getChecksum(), "");
- unmatchedByRuleAndLineAndChecksum.get(ruleKey).get(lineNotNull).get(checksumNotNull).remove(matching);
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/SourceHashHolder.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/SourceHashHolder.java
deleted file mode 100644
index 612968e8fc9..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/SourceHashHolder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import com.google.common.collect.ImmutableSet;
-import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.batch.scan.LastLineHashes;
-import org.sonar.plugins.core.issue.tracking.FileHashes;
-
-import javax.annotation.CheckForNull;
-
-import java.util.Collection;
-
-public class SourceHashHolder {
-
- private final LastLineHashes lastSnapshots;
-
- private FileHashes hashedReference;
- private FileHashes hashedSource;
- private DefaultInputFile inputFile;
-
- public SourceHashHolder(DefaultInputFile inputFile, LastLineHashes lastSnapshots) {
- this.inputFile = inputFile;
- this.lastSnapshots = lastSnapshots;
- }
-
- private void initHashes() {
- if (hashedSource == null) {
- hashedSource = FileHashes.create(inputFile.lineHashes());
- Status status = inputFile.status();
- if (status == Status.ADDED) {
- hashedReference = null;
- } else if (status == Status.SAME) {
- hashedReference = hashedSource;
- } else {
- String[] lineHashes = lastSnapshots.getLineHashes(inputFile.key());
- hashedReference = lineHashes != null ? FileHashes.create(lineHashes) : null;
- }
- }
- }
-
- @CheckForNull
- public FileHashes getHashedReference() {
- initHashes();
- return hashedReference;
- }
-
- public FileHashes getHashedSource() {
- initHashes();
- return hashedSource;
- }
-
- public Collection<Integer> getNewLinesMatching(Integer originLine) {
- FileHashes reference = getHashedReference();
- if (reference == null) {
- return ImmutableSet.of();
- } else {
- return getHashedSource().getLinesForHash(reference.getHash(originLine));
- }
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/FileHashes.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/FileHashes.java
deleted file mode 100644
index d45ac2d65cc..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/FileHashes.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.plugins.core.issue.tracking;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.lang.ObjectUtils;
-
-import java.util.Collection;
-
-/**
- * Wraps a {@link Sequence} to assign hash codes to elements.
- */
-public final class FileHashes {
-
- private final String[] hashes;
- private final Multimap<String, Integer> linesByHash;
-
- private FileHashes(String[] hashes, Multimap<String, Integer> linesByHash) {
- this.hashes = hashes;
- this.linesByHash = linesByHash;
- }
-
- public static FileHashes create(String[] hashes) {
- int size = hashes.length;
- Multimap<String, Integer> linesByHash = LinkedHashMultimap.create();
- for (int i = 0; i < size; i++) {
- // indices in array are shifted one line before
- linesByHash.put(hashes[i], i + 1);
- }
- return new FileHashes(hashes, linesByHash);
- }
-
- public static FileHashes create(byte[][] hashes) {
- int size = hashes.length;
- Multimap<String, Integer> linesByHash = LinkedHashMultimap.create();
- String[] hexHashes = new String[size];
- for (int i = 0; i < size; i++) {
- String hash = hashes[i] != null ? Hex.encodeHexString(hashes[i]) : "";
- hexHashes[i] = hash;
- // indices in array are shifted one line before
- linesByHash.put(hash, i + 1);
- }
- return new FileHashes(hexHashes, linesByHash);
- }
-
- public int length() {
- return hashes.length;
- }
-
- public Collection<Integer> getLinesForHash(String hash) {
- return linesByHash.get(hash);
- }
-
- public String getHash(int line) {
- // indices in array are shifted one line before
- return (String) ObjectUtils.defaultIfNull(hashes[line - 1], "");
- }
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizer.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizer.java
deleted file mode 100644
index 11611ad952d..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizer.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.plugins.core.issue.tracking;
-
-import javax.annotation.Nullable;
-
-public class IssueTrackingBlocksRecognizer {
-
- private final FileHashes a;
- private final FileHashes b;
-
- public IssueTrackingBlocksRecognizer(FileHashes a, FileHashes b) {
- this.a = a;
- this.b = b;
- }
-
- public boolean isValidLineInReference(@Nullable Integer line) {
- return (line != null) && (0 <= line - 1) && (line - 1 < a.length());
- }
-
- public boolean isValidLineInSource(@Nullable Integer line) {
- return (line != null) && (0 <= line - 1) && (line - 1 < b.length());
- }
-
- /**
- * @param startA number of line from first version of text (numbering starts from 1)
- * @param startB number of line from second version of text (numbering starts from 1)
- */
- public int computeLengthOfMaximalBlock(int startA, int startB) {
- if (!a.getHash(startA).equals(b.getHash(startB))) {
- return 0;
- }
- int length = 0;
- int ai = startA;
- int bi = startB;
- while (ai <= a.length() && bi <= b.length() && a.getHash(ai).equals(b.getHash(bi))) {
- ai++;
- bi++;
- length++;
- }
- ai = startA;
- bi = startB;
- while (ai > 0 && bi > 0 && a.getHash(ai).equals(b.getHash(bi))) {
- ai--;
- bi--;
- length++;
- }
- // Note that position (startA, startB) was counted twice
- return length - 1;
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/RollingFileHashes.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/RollingFileHashes.java
deleted file mode 100644
index 313507a4d69..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/RollingFileHashes.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.plugins.core.issue.tracking;
-
-/**
- * Compute hashes of block around each line
- */
-public class RollingFileHashes {
-
- final int[] rollingHashes;
-
- public static RollingFileHashes create(FileHashes hashes, int halfBlockSize) {
- int size = hashes.length();
- int[] rollingHashes = new int[size];
-
- RollingHashCalculator hashCalulator = new RollingHashCalculator(halfBlockSize * 2 + 1);
- for (int i = 1; i <= Math.min(size, halfBlockSize + 1); i++) {
- hashCalulator.add(hashes.getHash(i).hashCode());
- }
- for (int i = 1; i <= size; i++) {
- rollingHashes[i - 1] = hashCalulator.getHash();
- if (i - halfBlockSize > 0) {
- hashCalulator.remove(hashes.getHash(i - halfBlockSize).hashCode());
- }
- if (i + 1 + halfBlockSize <= size) {
- hashCalulator.add(hashes.getHash(i + 1 + halfBlockSize).hashCode());
- } else {
- hashCalulator.add(0);
- }
- }
-
- return new RollingFileHashes(rollingHashes);
- }
-
- public int getHash(int line) {
- return rollingHashes[line - 1];
- }
-
- private RollingFileHashes(int[] hashes) {
- this.rollingHashes = hashes;
- }
-
- private static class RollingHashCalculator {
-
- private static final int PRIME_BASE = 31;
-
- private final int power;
- private int hash;
-
- public RollingHashCalculator(int size) {
- int pow = 1;
- for (int i = 0; i < size - 1; i++) {
- pow = pow * PRIME_BASE;
- }
- this.power = pow;
- }
-
- public void add(int value) {
- hash = hash * PRIME_BASE + value;
- }
-
- public void remove(int value) {
- hash = hash - power * value;
- }
-
- public int getHash() {
- return hash;
- }
-
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/package-info.java
deleted file mode 100644
index 4a3c6986229..00000000000
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/tracking/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-@javax.annotation.ParametersAreNonnullByDefault
-package org.sonar.plugins.core.issue.tracking;
-
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensorTest.java
deleted file mode 100644
index e1c70330963..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesSensorTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.apache.ibatis.session.ResultHandler;
-import org.junit.Test;
-import org.sonar.api.resources.Project;
-import org.sonar.core.issue.db.IssueChangeDao;
-import org.sonar.core.issue.db.IssueDao;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class InitialOpenIssuesSensorTest {
-
- InitialOpenIssuesStack stack = mock(InitialOpenIssuesStack.class);
- IssueDao issueDao = mock(IssueDao.class);
- IssueChangeDao issueChangeDao = mock(IssueChangeDao.class);
-
- InitialOpenIssuesSensor sensor = new InitialOpenIssuesSensor(stack, issueDao, issueChangeDao);
-
- @Test
- public void should_select_module_open_issues() {
- Project project = new Project("key");
- project.setId(1);
- sensor.analyse(project, null);
-
- verify(issueDao).selectNonClosedIssuesByModule(eq(1), any(ResultHandler.class));
- }
-
- @Test
- public void should_select_module_open_issues_changelog() {
- Project project = new Project("key");
- project.setId(1);
- sensor.analyse(project, null);
-
- verify(issueChangeDao).selectChangelogOnNonClosedIssuesByModuleAndType(eq(1), any(ResultHandler.class));
- }
-
- @Test
- public void test_toString() throws Exception {
- assertThat(sensor.toString()).isEqualTo("InitialOpenIssuesSensor");
-
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesStackTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesStackTest.java
deleted file mode 100644
index ed7782e138b..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/InitialOpenIssuesStackTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.batch.bootstrap.BootstrapProperties;
-import org.sonar.batch.bootstrap.TempFolderProvider;
-import org.sonar.batch.index.Caches;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class InitialOpenIssuesStackTest {
-
- @ClassRule
- public static TemporaryFolder temp = new TemporaryFolder();
-
- public static Caches createCacheOnTemp(TemporaryFolder temp) {
- BootstrapProperties bootstrapSettings = new BootstrapProperties(Collections.<String, String>emptyMap());
- try {
- bootstrapSettings.properties().put(CoreProperties.WORKING_DIRECTORY, temp.newFolder().getAbsolutePath());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return new Caches(new TempFolderProvider().provide(bootstrapSettings));
- }
-
- InitialOpenIssuesStack stack;
- Caches caches;
-
- @Before
- public void before() throws Exception {
- caches = createCacheOnTemp(temp);
- caches.start();
- stack = new InitialOpenIssuesStack(caches);
- }
-
- @After
- public void after() {
- caches.stop();
- }
-
- @Test
- public void get_and_remove_issues() {
- IssueDto issueDto = new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1");
- stack.addIssue(issueDto);
-
- List<IssueDto> issueDtos = stack.selectAndRemoveIssues("org.struts.Action");
- assertThat(issueDtos).hasSize(1);
- assertThat(issueDtos.get(0).getKee()).isEqualTo("ISSUE-1");
-
- assertThat(stack.selectAllIssues()).isEmpty();
- }
-
- @Test
- public void get_and_remove_with_many_issues_on_same_resource() {
- stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
- stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-2"));
-
- List<IssueDto> issueDtos = stack.selectAndRemoveIssues("org.struts.Action");
- assertThat(issueDtos).hasSize(2);
-
- assertThat(stack.selectAllIssues()).isEmpty();
- }
-
- @Test
- public void get_and_remove_do_nothing_if_resource_not_found() {
- stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
-
- List<IssueDto> issueDtos = stack.selectAndRemoveIssues("Other");
- assertThat(issueDtos).hasSize(0);
-
- assertThat(stack.selectAllIssues()).hasSize(1);
- }
-
- @Test
- public void select_changelog() {
- stack.addChangelog(new IssueChangeDto().setKey("CHANGE-1").setIssueKey("ISSUE-1"));
- stack.addChangelog(new IssueChangeDto().setKey("CHANGE-2").setIssueKey("ISSUE-1"));
-
- List<IssueChangeDto> issueChangeDtos = stack.selectChangelog("ISSUE-1");
- assertThat(issueChangeDtos).hasSize(2);
- assertThat(issueChangeDtos.get(0).getKey()).isEqualTo("CHANGE-1");
- assertThat(issueChangeDtos.get(1).getKey()).isEqualTo("CHANGE-2");
- }
-
- @Test
- public void return_empty_changelog() {
- assertThat(stack.selectChangelog("ISSUE-1")).isEmpty();
- }
-
- @Test
- public void clear_issues() {
- stack.addIssue(new IssueDto().setComponentKey("org.struts.Action").setKee("ISSUE-1"));
-
- assertThat(stack.selectAllIssues()).hasSize(1);
-
- // issues are not removed
- assertThat(stack.selectAllIssues()).hasSize(1);
-
- stack.clear();
- assertThat(stack.selectAllIssues()).isEmpty();
- }
-
- @Test
- public void clear_issues_changelog() {
- stack.addChangelog(new IssueChangeDto().setKey("CHANGE-1").setIssueKey("ISSUE-1"));
-
- assertThat(stack.selectChangelog("ISSUE-1")).hasSize(1);
-
- stack.clear();
- assertThat(stack.selectChangelog("ISSUE-1")).isEmpty();
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueHandlersTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueHandlersTest.java
deleted file mode 100644
index b1f745927e5..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueHandlersTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.issue.IssueHandler;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
-
-import java.util.Date;
-
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
-
-public class IssueHandlersTest {
- @Test
- public void should_execute_handlers() throws Exception {
- IssueHandler h1 = mock(IssueHandler.class);
- IssueHandler h2 = mock(IssueHandler.class);
- IssueUpdater updater = mock(IssueUpdater.class);
-
- IssueHandlers handlers = new IssueHandlers(updater, new IssueHandler[]{h1, h2});
- final DefaultIssue issue = new DefaultIssue();
- handlers.execute(issue, IssueChangeContext.createScan(new Date()));
-
- verify(h1).onIssue(argThat(new ArgumentMatcher<IssueHandler.Context>() {
- @Override
- public boolean matches(Object o) {
- return ((IssueHandler.Context) o).issue() == issue;
- }
- }));
- }
-
- @Test
- public void test_no_handlers() {
- IssueUpdater updater = mock(IssueUpdater.class);
- IssueHandlers handlers = new IssueHandlers(updater);
- handlers.execute(new DefaultIssue(), IssueChangeContext.createScan(new Date()));
- verifyZeroInteractions(updater);
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
deleted file mode 100644
index 337f16b94fe..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.apache.commons.codec.digest.DigestUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.System2;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.scan.LastLineHashes;
-import org.sonar.batch.scan.filesystem.InputPathCache;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.db.IssueChangeDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.workflow.IssueWorkflow;
-import org.sonar.java.api.JavaClass;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyCollection;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.*;
-
-public class IssueTrackingDecoratorTest {
-
- IssueTrackingDecorator decorator;
- IssueCache issueCache = mock(IssueCache.class, RETURNS_MOCKS);
- InitialOpenIssuesStack initialOpenIssues = mock(InitialOpenIssuesStack.class);
- IssueTracking tracking = mock(IssueTracking.class, RETURNS_MOCKS);
- LastLineHashes lastSnapshots = mock(LastLineHashes.class);
- IssueHandlers handlers = mock(IssueHandlers.class);
- IssueWorkflow workflow = mock(IssueWorkflow.class);
- IssueUpdater updater = mock(IssueUpdater.class);
- ResourcePerspectives perspectives = mock(ResourcePerspectives.class);
- RulesProfile profile = mock(RulesProfile.class);
- RuleFinder ruleFinder = mock(RuleFinder.class);
- InputPathCache inputPathCache = mock(InputPathCache.class);
-
- @Before
- public void init() {
- decorator = new IssueTrackingDecorator(
- issueCache,
- initialOpenIssues,
- tracking,
- lastSnapshots,
- handlers,
- workflow,
- updater,
- new Project("foo"),
- perspectives,
- profile,
- ruleFinder,
- inputPathCache);
- }
-
- @Test
- public void should_execute_on_project() {
- Project project = mock(Project.class);
- assertThat(decorator.shouldExecuteOnProject(project)).isTrue();
- }
-
- @Test
- public void should_not_be_executed_on_classes_not_methods() throws Exception {
- DecoratorContext context = mock(DecoratorContext.class);
- decorator.decorate(JavaClass.create("org.foo.Bar"), context);
- verifyZeroInteractions(context, issueCache, tracking, handlers, workflow);
- }
-
- @Test
- public void should_process_open_issues() throws Exception {
- Resource file = File.create("Action.java").setEffectiveKey("struts:Action.java").setId(123);
- final DefaultIssue issue = new DefaultIssue();
-
- // INPUT : one issue, no open issues during previous scan, no filtering
- when(issueCache.byComponent("struts:Action.java")).thenReturn(Arrays.asList(issue));
- List<IssueDto> dbIssues = Collections.emptyList();
- when(initialOpenIssues.selectAndRemoveIssues("struts:Action.java")).thenReturn(dbIssues);
- when(inputPathCache.getFile("foo", "Action.java")).thenReturn(mock(DefaultInputFile.class));
- decorator.doDecorate(file);
-
- // Apply filters, track, apply transitions, notify extensions then update cache
- verify(tracking).track(isA(SourceHashHolder.class), eq(dbIssues), argThat(new ArgumentMatcher<Collection<DefaultIssue>>() {
- @Override
- public boolean matches(Object o) {
- List<DefaultIssue> issues = (List<DefaultIssue>) o;
- return issues.size() == 1 && issues.get(0) == issue;
- }
- }));
- verify(workflow).doAutomaticTransition(eq(issue), any(IssueChangeContext.class));
- verify(handlers).execute(eq(issue), any(IssueChangeContext.class));
- verify(issueCache).put(issue);
- }
-
- @Test
- public void should_register_unmatched_issues_as_end_of_life() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
- Resource file = File.create("Action.java").setEffectiveKey("struts:Action.java").setId(123);
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle");
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
- when(inputPathCache.getFile("foo", "Action.java")).thenReturn(mock(DefaultInputFile.class));
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isTrue();
- }
-
- @Test
- public void manual_issues_should_be_moved_if_matching_line_found() throws Exception {
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(6).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public interface Action {\n"
- + " void method1();\n"
- + " void method2();\n"
- + " void method3();\n"
- + " void method4();\n"
- + " void method5();\n" // Original issue here
- + "}";
- String newSource = "public interface Action {\n"
- + " void method5();\n" // New issue here
- + " void method1();\n"
- + " void method2();\n"
- + " void method3();\n"
- + " void method4();\n"
- + "}";
- Resource file = mockHashes(originalSource, newSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.line()).isEqualTo(2);
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isFalse();
- assertThat(issue.isOnDisabledRule()).isFalse();
- }
-
- private Resource mockHashes(String originalSource, String newSource) {
- DefaultInputFile inputFile = mock(DefaultInputFile.class);
- byte[][] hashes = computeHashes(newSource);
- when(inputFile.lineHashes()).thenReturn(hashes);
- when(inputFile.key()).thenReturn("foo:Action.java");
- when(inputPathCache.getFile("foo", "Action.java")).thenReturn(inputFile);
- when(lastSnapshots.getLineHashes("foo:Action.java")).thenReturn(computeHexHashes(originalSource));
- Resource file = File.create("Action.java");
- return file;
- }
-
- @Test
- public void manual_issues_should_be_untouched_if_already_closed() throws Exception {
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("CLOSED").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public interface Action {}";
- Resource file = mockHashes(originalSource, originalSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.line()).isEqualTo(1);
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isFalse();
- assertThat(issue.isOnDisabledRule()).isFalse();
- assertThat(issue.status()).isEqualTo("CLOSED");
- }
-
- @Test
- public void manual_issues_should_be_untouched_if_line_is_null() throws Exception {
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(null).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public interface Action {}";
- Resource file = mockHashes(originalSource, originalSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.line()).isEqualTo(null);
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isFalse();
- assertThat(issue.isOnDisabledRule()).isFalse();
- assertThat(issue.status()).isEqualTo("OPEN");
- }
-
- @Test
- public void manual_issues_should_be_kept_if_matching_line_not_found() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
- // INPUT : one issue existing during previous scan
- final int issueOnLine = 6;
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(issueOnLine).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public interface Action {\n"
- + " void method1();\n"
- + " void method2();\n"
- + " void method3();\n"
- + " void method4();\n"
- + " void method5();\n" // Original issue here
- + "}";
- String newSource = "public interface Action {\n"
- + " void method1();\n"
- + " void method2();\n"
- + " void method3();\n"
- + " void method4();\n"
- + " void method6();\n" // Poof, no method5 anymore
- + "}";
-
- Resource file = mockHashes(originalSource, newSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.line()).isEqualTo(issueOnLine);
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isFalse();
- assertThat(issue.isOnDisabledRule()).isFalse();
- }
-
- @Test
- public void manual_issues_should_be_kept_if_multiple_matching_lines_found() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
- // INPUT : one issue existing during previous scan
- final int issueOnLine = 3;
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(issueOnLine).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance"));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public class Action {\n"
- + " void method1() {\n"
- + " notify();\n" // initial issue
- + " }\n"
- + "}";
- String newSource = "public class Action {\n"
- + " \n"
- + " void method1() {\n" // new issue will appear here
- + " notify();\n"
- + " }\n"
- + " void method2() {\n"
- + " notify();\n"
- + " }\n"
- + "}";
- Resource file = mockHashes(originalSource, newSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.line()).isEqualTo(issueOnLine);
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isFalse();
- assertThat(issue.isOnDisabledRule()).isFalse();
- }
-
- @Test
- public void manual_issues_should_be_closed_if_manual_rule_is_removed() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(new Rule("manual", "Performance").setStatus(Rule.STATUS_REMOVED));
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String source = "public interface Action {}";
- Resource file = mockHashes(source, source);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isTrue();
- assertThat(issue.isOnDisabledRule()).isTrue();
- }
-
- @Test
- public void manual_issues_should_be_closed_if_manual_rule_is_not_found() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(1).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(null);
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String source = "public interface Action {}";
- Resource file = mockHashes(source, source);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isTrue();
- assertThat(issue.isOnDisabledRule()).isTrue();
- }
-
- @Test
- public void manual_issues_should_be_closed_if_new_source_is_shorter() throws Exception {
- // "Unmatched" issues existed in previous scan but not in current one -> they have to be closed
-
- // INPUT : one issue existing during previous scan
- IssueDto unmatchedIssue = new IssueDto().setKee("ABCDE").setReporter("freddy").setLine(6).setStatus("OPEN").setRuleKey("manual", "Performance");
- when(ruleFinder.findByKey(RuleKey.of("manual", "Performance"))).thenReturn(null);
-
- IssueTrackingResult trackingResult = new IssueTrackingResult();
- trackingResult.addUnmatched(unmatchedIssue);
-
- String originalSource = "public interface Action {\n"
- + " void method1();\n"
- + " void method2();\n"
- + " void method3();\n"
- + " void method4();\n"
- + " void method5();\n"
- + "}";
- String newSource = "public interface Action {\n"
- + " void method1();\n"
- + " void method2();\n"
- + "}";
- Resource file = mockHashes(originalSource, newSource);
-
- when(tracking.track(isA(SourceHashHolder.class), anyCollection(), anyCollection())).thenReturn(trackingResult);
-
- decorator.doDecorate(file);
-
- verify(workflow, times(1)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(1)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
-
- ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
- verify(issueCache).put(argument.capture());
-
- DefaultIssue issue = argument.getValue();
- verify(updater).setResolution(eq(issue), eq(Issue.RESOLUTION_REMOVED), any(IssueChangeContext.class));
- verify(updater).setStatus(eq(issue), eq(Issue.STATUS_CLOSED), any(IssueChangeContext.class));
-
- assertThat(issue.key()).isEqualTo("ABCDE");
- assertThat(issue.isNew()).isFalse();
- assertThat(issue.isEndOfLife()).isTrue();
- assertThat(issue.isOnDisabledRule()).isTrue();
- }
-
- @Test
- public void should_register_issues_on_deleted_components() throws Exception {
- Project project = new Project("struts");
- DefaultIssue openIssue = new DefaultIssue();
- when(issueCache.byComponent("struts")).thenReturn(Arrays.asList(openIssue));
- IssueDto deadIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle");
- when(initialOpenIssues.selectAllIssues()).thenReturn(Arrays.asList(deadIssue));
-
- decorator.doDecorate(project);
-
- // the dead issue must be closed -> apply automatic transition, notify handlers and add to cache
- verify(workflow, times(2)).doAutomaticTransition(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(handlers, times(2)).execute(any(DefaultIssue.class), any(IssueChangeContext.class));
- verify(issueCache, times(2)).put(any(DefaultIssue.class));
-
- verify(issueCache).put(argThat(new ArgumentMatcher<DefaultIssue>() {
- @Override
- public boolean matches(Object o) {
- DefaultIssue dead = (DefaultIssue) o;
- return "ABCDE".equals(dead.key()) && !dead.isNew() && dead.isEndOfLife();
- }
- }));
- }
-
- @Test
- public void merge_matched_issue() throws Exception {
- IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
- .setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L).setProjectKey("sample");
- DefaultIssue issue = new DefaultIssue();
-
- IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
- when(trackingResult.matched()).thenReturn(newArrayList(issue));
- when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
- decorator.mergeMatched(trackingResult);
-
- verify(updater).setPastSeverity(eq(issue), eq("MAJOR"), any(IssueChangeContext.class));
- verify(updater).setPastLine(eq(issue), eq(10));
- verify(updater).setPastMessage(eq(issue), eq("Message"), any(IssueChangeContext.class));
- verify(updater).setPastEffortToFix(eq(issue), eq(1.5), any(IssueChangeContext.class));
- verify(updater).setPastTechnicalDebt(eq(issue), eq(Duration.create(1L)), any(IssueChangeContext.class));
- verify(updater).setPastProject(eq(issue), eq("sample"), any(IssueChangeContext.class));
- }
-
- @Test
- public void merge_matched_issue_on_manual_severity() throws Exception {
- IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
- .setLine(10).setManualSeverity(true).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L);
- DefaultIssue issue = new DefaultIssue();
-
- IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
- when(trackingResult.matched()).thenReturn(newArrayList(issue));
- when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
- decorator.mergeMatched(trackingResult);
-
- assertThat(issue.manualSeverity()).isTrue();
- assertThat(issue.severity()).isEqualTo("MAJOR");
- verify(updater, never()).setPastSeverity(eq(issue), anyString(), any(IssueChangeContext.class));
- }
-
- @Test
- public void merge_issue_changelog_with_previous_changelog() throws Exception {
- when(initialOpenIssues.selectChangelog("ABCDE")).thenReturn(newArrayList(new IssueChangeDto().setIssueKey("ABCD").setCreatedAt(System2.INSTANCE.now())));
-
- IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey("squid", "AvoidCycle")
- .setLine(10).setMessage("Message").setEffortToFix(1.5).setDebt(1L).setCreatedAt(System2.INSTANCE.now());
- DefaultIssue issue = new DefaultIssue();
-
- IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
- when(trackingResult.matched()).thenReturn(newArrayList(issue));
- when(trackingResult.matching(eq(issue))).thenReturn(previousIssue);
- decorator.mergeMatched(trackingResult);
-
- assertThat(issue.changes()).hasSize(1);
- }
-
- private byte[][] computeHashes(String source) {
- String[] lines = source.split("\n");
- byte[][] hashes = new byte[lines.length][];
- for (int i = 0; i < lines.length; i++) {
- hashes[i] = DigestUtils.md5(lines[i].replaceAll("[\t ]", ""));
- }
- return hashes;
- }
-
- private String[] computeHexHashes(String source) {
- String[] lines = source.split("\n");
- String[] hashes = new String[lines.length];
- for (int i = 0; i < lines.length; i++) {
- hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", ""));
- }
- return hashes;
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java
deleted file mode 100644
index 7fb8b6a9103..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Resources;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.batch.scan.LastLineHashes;
-import org.sonar.core.issue.db.IssueDto;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-public class IssueTrackingTest {
-
- IssueTracking tracking;
- Resource project;
- SourceHashHolder sourceHashHolder;
- LastLineHashes lastSnapshots;
- long violationId = 0;
-
- @Before
- public void before() {
- lastSnapshots = mock(LastLineHashes.class);
-
- project = mock(Project.class);
- tracking = new IssueTracking();
- }
-
- @Test
- public void key_should_be_the_prioritary_field_to_check() {
- IssueDto referenceIssue1 = newReferenceIssue("message", 10, "squid", "AvoidCycle", "checksum1").setKee("100");
- IssueDto referenceIssue2 = newReferenceIssue("message", 10, "squid", "AvoidCycle", "checksum2").setKee("200");
-
- // exactly the fields of referenceIssue1 but not the same key
- DefaultIssue newIssue = newDefaultIssue("message", 10, RuleKey.of("squid", "AvoidCycle"), "checksum1").setKey("200");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue1, referenceIssue2), null, result);
- // same key
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue2);
- }
-
- @Test
- public void checksum_should_have_greater_priority_than_line() {
- IssueDto referenceIssue1 = newReferenceIssue("message", 1, "squid", "AvoidCycle", "checksum1");
- IssueDto referenceIssue2 = newReferenceIssue("message", 3, "squid", "AvoidCycle", "checksum2");
-
- DefaultIssue newIssue1 = newDefaultIssue("message", 3, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- DefaultIssue newIssue2 = newDefaultIssue("message", 5, RuleKey.of("squid", "AvoidCycle"), "checksum2");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue1, newIssue2), newArrayList(referenceIssue1, referenceIssue2), null, result);
- assertThat(result.matching(newIssue1)).isSameAs(referenceIssue1);
- assertThat(result.matching(newIssue2)).isSameAs(referenceIssue2);
- }
-
- /**
- * SONAR-2928
- */
- @Test
- public void same_rule_and_null_line_and_checksum_but_different_messages() {
- DefaultIssue newIssue = newDefaultIssue("new message", null, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("old message", null, "squid", "AvoidCycle", "checksum1");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- @Test
- public void same_rule_and_line_and_checksum_but_different_messages() {
- DefaultIssue newIssue = newDefaultIssue("new message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("old message", 1, "squid", "AvoidCycle", "checksum1");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- @Test
- public void same_rule_and_line_message() {
- DefaultIssue newIssue = newDefaultIssue("message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("message", 1, "squid", "AvoidCycle", "checksum2");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- @Test
- public void should_ignore_reference_measure_without_checksum() {
- DefaultIssue newIssue = newDefaultIssue("message", 1, RuleKey.of("squid", "AvoidCycle"), null);
- IssueDto referenceIssue = newReferenceIssue("message", 1, "squid", "NullDeref", null);
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isNull();
- }
-
- @Test
- public void same_rule_and_message_and_checksum_but_different_line() {
- DefaultIssue newIssue = newDefaultIssue("message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("message", 2, "squid", "AvoidCycle", "checksum1");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- /**
- * SONAR-2812
- */
- @Test
- public void same_checksum_and_rule_but_different_line_and_different_message() {
- DefaultIssue newIssue = newDefaultIssue("new message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("old message", 2, "squid", "AvoidCycle", "checksum1");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- @Test
- public void should_create_new_issue_when_same_rule_same_message_but_different_line_and_checksum() {
- DefaultIssue newIssue = newDefaultIssue("message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("message", 2, "squid", "AvoidCycle", "checksum2");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isNull();
- }
-
- @Test
- public void should_not_track_issue_if_different_rule() {
- DefaultIssue newIssue = newDefaultIssue("message", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("message", 1, "squid", "NullDeref", "checksum1");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isNull();
- }
-
- @Test
- public void should_compare_issues_with_database_format() {
- // issue messages are trimmed and can be abbreviated when persisted in database.
- // Comparing issue messages must use the same format.
- DefaultIssue newIssue = newDefaultIssue(" message ", 1, RuleKey.of("squid", "AvoidCycle"), "checksum1");
- IssueDto referenceIssue = newReferenceIssue("message", 1, "squid", "AvoidCycle", "checksum2");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(newArrayList(newIssue), newArrayList(referenceIssue), null, result);
- assertThat(result.matching(newIssue)).isSameAs(referenceIssue);
- }
-
- @Test
- public void past_issue_not_associated_with_line_should_not_cause_npe() throws Exception {
- initLastHashes("example2-v1", "example2-v2");
-
- DefaultIssue newIssue = newDefaultIssue("Indentation", 9, RuleKey.of("squid", "AvoidCycle"), "foo");
- IssueDto referenceIssue = newReferenceIssue("2 branches need to be covered", null, "squid", "AvoidCycle", null);
-
- IssueTrackingResult result = tracking.track(sourceHashHolder, newArrayList(referenceIssue), newArrayList(newIssue));
-
- assertThat(result.matched()).isEmpty();
- }
-
- @Test
- public void new_issue_not_associated_with_line_should_not_cause_npe() throws Exception {
- initLastHashes("example2-v1", "example2-v2");
-
- DefaultIssue newIssue = newDefaultIssue("1 branch need to be covered", null, RuleKey.of("squid", "AvoidCycle"), "foo");
- IssueDto referenceIssue = newReferenceIssue("Indentationd", 7, "squid", "AvoidCycle", null);
-
- IssueTrackingResult result = tracking.track(sourceHashHolder, newArrayList(referenceIssue), newArrayList(newIssue));
-
- assertThat(result.matched()).isEmpty();
- }
-
- /**
- * SONAR-2928
- */
- @Test
- public void issue_not_associated_with_line() throws Exception {
- initLastHashes("example2-v1", "example2-v2");
-
- DefaultIssue newIssue = newDefaultIssue("1 branch need to be covered", null, RuleKey.of("squid", "AvoidCycle"), null);
- IssueDto referenceIssue = newReferenceIssue("2 branches need to be covered", null, "squid", "AvoidCycle", null);
-
- IssueTrackingResult result = tracking.track(sourceHashHolder, newArrayList(referenceIssue), newArrayList(newIssue));
-
- assertThat(result.matching(newIssue)).isEqualTo(referenceIssue);
- }
-
- /**
- * SONAR-3072
- */
- @Test
- public void should_track_issues_based_on_blocks_recognition_on_example1() throws Exception {
- initLastHashes("example1-v1", "example1-v2");
-
- IssueDto referenceIssue1 = newReferenceIssue("Indentation", 7, "squid", "AvoidCycle", null);
- IssueDto referenceIssue2 = newReferenceIssue("Indentation", 11, "squid", "AvoidCycle", null);
-
- DefaultIssue newIssue1 = newDefaultIssue("Indentation", 9, RuleKey.of("squid", "AvoidCycle"), null);
- DefaultIssue newIssue2 = newDefaultIssue("Indentation", 13, RuleKey.of("squid", "AvoidCycle"), null);
- DefaultIssue newIssue3 = newDefaultIssue("Indentation", 17, RuleKey.of("squid", "AvoidCycle"), null);
- DefaultIssue newIssue4 = newDefaultIssue("Indentation", 21, RuleKey.of("squid", "AvoidCycle"), null);
-
- IssueTrackingResult result = tracking.track(sourceHashHolder, Arrays.asList(referenceIssue1, referenceIssue2), Arrays.asList(newIssue1, newIssue2, newIssue3, newIssue4));
-
- assertThat(result.matching(newIssue1)).isNull();
- assertThat(result.matching(newIssue2)).isNull();
- assertThat(result.matching(newIssue3)).isSameAs(referenceIssue1);
- assertThat(result.matching(newIssue4)).isSameAs(referenceIssue2);
- }
-
- /**
- * SONAR-3072
- */
- @Test
- public void should_track_issues_based_on_blocks_recognition_on_example2() throws Exception {
- initLastHashes("example2-v1", "example2-v2");
-
- IssueDto referenceIssue1 = newReferenceIssue("SystemPrintln", 5, "squid", "AvoidCycle", null);
-
- DefaultIssue newIssue1 = newDefaultIssue("SystemPrintln", 6, RuleKey.of("squid", "AvoidCycle"), null);
- DefaultIssue newIssue2 = newDefaultIssue("SystemPrintln", 10, RuleKey.of("squid", "AvoidCycle"), null);
- DefaultIssue newIssue3 = newDefaultIssue("SystemPrintln", 14, RuleKey.of("squid", "AvoidCycle"), null);
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(
- Arrays.asList(newIssue1, newIssue2, newIssue3),
- Arrays.asList(referenceIssue1),
- sourceHashHolder, result);
-
- assertThat(result.matching(newIssue1)).isNull();
- assertThat(result.matching(newIssue2)).isSameAs(referenceIssue1);
- assertThat(result.matching(newIssue3)).isNull();
- }
-
- @Test
- public void should_track_issues_based_on_blocks_recognition_on_example3() throws Exception {
- initLastHashes("example3-v1", "example3-v2");
-
- IssueDto referenceIssue1 = newReferenceIssue("Avoid unused local variables such as 'j'.", 6, "squid", "AvoidCycle", "63c11570fc0a76434156be5f8138fa03");
- IssueDto referenceIssue2 = newReferenceIssue("Avoid unused private methods such as 'myMethod()'.", 13, "squid", "NullDeref", "ef23288705d1ef1e512448ace287586e");
- IssueDto referenceIssue3 = newReferenceIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, "pmd",
- "UnusedLocalVariable", "ed5cdd046fda82727d6fedd1d8e3a310");
-
- // New issue
- DefaultIssue newIssue1 = newDefaultIssue("Avoid unused local variables such as 'msg'.", 18, RuleKey.of("squid", "AvoidCycle"), "a24254126be2bf1a9b9a8db43f633733");
- // Same as referenceIssue2
- DefaultIssue newIssue2 = newDefaultIssue("Avoid unused private methods such as 'myMethod()'.", 13, RuleKey.of("squid", "NullDeref"), "ef23288705d1ef1e512448ace287586e");
- // Same as referenceIssue3
- DefaultIssue newIssue3 = newDefaultIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9,
- RuleKey.of("pmd", "UnusedLocalVariable"), "ed5cdd046fda82727d6fedd1d8e3a310");
- // New issue
- DefaultIssue newIssue4 = newDefaultIssue("Method 'newViolation' is not designed for extension - needs to be abstract, final or empty.", 17,
- RuleKey.of("pmd", "UnusedLocalVariable"), "7d58ac9040c27e4ca2f11a0269e251e2");
- // Same as referenceIssue1
- DefaultIssue newIssue5 = newDefaultIssue("Avoid unused local variables such as 'j'.", 6, RuleKey.of("squid", "AvoidCycle"), "4432a2675ec3e1620daefe38386b51ef");
-
- IssueTrackingResult result = new IssueTrackingResult();
- tracking.mapIssues(
- Arrays.asList(newIssue1, newIssue2, newIssue3, newIssue4, newIssue5),
- Arrays.asList(referenceIssue1, referenceIssue2, referenceIssue3),
- sourceHashHolder, result);
-
- assertThat(result.matching(newIssue1)).isNull();
- assertThat(result.matching(newIssue2)).isSameAs(referenceIssue2);
- assertThat(result.matching(newIssue3)).isSameAs(referenceIssue3);
- assertThat(result.matching(newIssue4)).isNull();
- assertThat(result.matching(newIssue5)).isSameAs(referenceIssue1);
- }
-
- @Test
- public void dont_load_checksum_if_no_new_issue() throws Exception {
- sourceHashHolder = mock(SourceHashHolder.class);
-
- IssueDto referenceIssue = newReferenceIssue("2 branches need to be covered", null, "squid", "AvoidCycle", null);
-
- tracking.track(sourceHashHolder, newArrayList(referenceIssue), Collections.<DefaultIssue>emptyList());
-
- verifyZeroInteractions(lastSnapshots, sourceHashHolder);
- }
-
- private static String load(String name) throws IOException {
- return Resources.toString(IssueTrackingTest.class.getResource("IssueTrackingTest/" + name + ".txt"), Charsets.UTF_8);
- }
-
- private DefaultIssue newDefaultIssue(String message, Integer line, RuleKey ruleKey, String checksum) {
- return new DefaultIssue().setMessage(message).setLine(line).setRuleKey(ruleKey).setChecksum(checksum).setStatus(Issue.STATUS_OPEN);
- }
-
- private IssueDto newReferenceIssue(String message, Integer lineId, String ruleRepo, String ruleKey, String lineChecksum) {
- IssueDto referenceIssue = new IssueDto();
- Long id = violationId++;
- referenceIssue.setId(id);
- referenceIssue.setKee(Long.toString(id));
- referenceIssue.setLine(lineId);
- referenceIssue.setMessage(message);
- referenceIssue.setRuleKey(ruleRepo, ruleKey);
- referenceIssue.setChecksum(lineChecksum);
- referenceIssue.setResolution(null);
- referenceIssue.setStatus(Issue.STATUS_OPEN);
- return referenceIssue;
- }
-
- private void initLastHashes(String reference, String newSource) throws IOException {
- DefaultInputFile inputFile = mock(DefaultInputFile.class);
- byte[][] hashes = computeHashes(load(newSource));
- when(inputFile.lineHashes()).thenReturn(hashes);
- when(inputFile.key()).thenReturn("foo:Action.java");
- when(lastSnapshots.getLineHashes("foo:Action.java")).thenReturn(computeHexHashes(load(reference)));
- sourceHashHolder = new SourceHashHolder(inputFile, lastSnapshots);
- }
-
- private byte[][] computeHashes(String source) {
- String[] lines = source.split("\n");
- byte[][] hashes = new byte[lines.length][];
- for (int i = 0; i < lines.length; i++) {
- hashes[i] = DigestUtils.md5(lines[i].replaceAll("[\t ]", ""));
- }
- return hashes;
- }
-
- private String[] computeHexHashes(String source) {
- String[] lines = source.split("\n");
- String[] hashes = new String[lines.length];
- for (int i = 0; i < lines.length; i++) {
- hashes[i] = DigestUtils.md5Hex(lines[i].replaceAll("[\t ]", ""));
- }
- return hashes;
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/SourceHashHolderTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/SourceHashHolderTest.java
deleted file mode 100644
index c9942c852b4..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/SourceHashHolderTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.plugins.core.issue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.batch.scan.LastLineHashes;
-
-import static org.apache.commons.codec.digest.DigestUtils.md5;
-import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class SourceHashHolderTest {
-
- SourceHashHolder sourceHashHolder;
-
- LastLineHashes lastSnapshots;
- DefaultInputFile file;
-
- @Before
- public void setUp() {
- lastSnapshots = mock(LastLineHashes.class);
- file = mock(DefaultInputFile.class);
-
- sourceHashHolder = new SourceHashHolder(file, lastSnapshots);
- }
-
- @Test
- public void should_lazy_load_line_hashes() {
- final String source = "source";
- when(file.lineHashes()).thenReturn(new byte[][] {md5(source), null});
-
- assertThat(sourceHashHolder.getHashedSource().getHash(1)).isEqualTo(md5Hex(source));
- assertThat(sourceHashHolder.getHashedSource().getHash(2)).isEqualTo("");
- verify(file).lineHashes();
- verify(file).key();
- verify(file).status();
-
- assertThat(sourceHashHolder.getHashedSource().getHash(1)).isEqualTo(md5Hex(source));
- Mockito.verifyNoMoreInteractions(file);
- }
-
- @Test
- public void should_lazy_load_reference_hashes_when_status_changed() {
- final String source = "source";
- String key = "foo:src/Foo.java";
- when(file.lineHashes()).thenReturn(new byte[][] {md5(source)});
- when(file.key()).thenReturn(key);
- when(file.status()).thenReturn(InputFile.Status.CHANGED);
- when(lastSnapshots.getLineHashes(key)).thenReturn(new String[] {md5Hex(source)});
-
- assertThat(sourceHashHolder.getHashedReference().getHash(1)).isEqualTo(md5Hex(source));
- verify(lastSnapshots).getLineHashes(key);
-
- assertThat(sourceHashHolder.getHashedReference().getHash(1)).isEqualTo(md5Hex(source));
- Mockito.verifyNoMoreInteractions(lastSnapshots);
- }
-
- @Test
- public void should_not_load_reference_hashes_when_status_same() {
- final String source = "source";
- String key = "foo:src/Foo.java";
- when(file.lineHashes()).thenReturn(new byte[][] {md5(source)});
- when(file.key()).thenReturn(key);
- when(file.status()).thenReturn(InputFile.Status.SAME);
-
- assertThat(sourceHashHolder.getHashedReference().getHash(1)).isEqualTo(md5Hex(source));
- assertThat(sourceHashHolder.getHashedReference().getHash(1)).isEqualTo(md5Hex(source));
- Mockito.verifyNoMoreInteractions(lastSnapshots);
- }
-
- @Test
- public void no_reference_hashes_when_status_added() {
- final String source = "source";
- String key = "foo:src/Foo.java";
- when(file.lineHashes()).thenReturn(new byte[][] {md5(source)});
- when(file.key()).thenReturn(key);
- when(file.status()).thenReturn(InputFile.Status.ADDED);
-
- assertThat(sourceHashHolder.getHashedReference()).isNull();
- Mockito.verifyNoMoreInteractions(lastSnapshots);
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizerTest.java
deleted file mode 100644
index 55d84685253..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/IssueTrackingBlocksRecognizerTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.plugins.core.issue.tracking;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IssueTrackingBlocksRecognizerTest {
-
- @Test
- public void test() {
- assertThat(compute(t("abcde"), t("abcde"), 4, 4)).isEqualTo(5);
- assertThat(compute(t("abcde"), t("abcd"), 4, 4)).isEqualTo(4);
- assertThat(compute(t("bcde"), t("abcde"), 4, 4)).isEqualTo(0);
- assertThat(compute(t("bcde"), t("abcde"), 3, 4)).isEqualTo(4);
- }
-
- private static int compute(FileHashes a, FileHashes b, int ai, int bi) {
- IssueTrackingBlocksRecognizer rec = new IssueTrackingBlocksRecognizer(a, b);
- return rec.computeLengthOfMaximalBlock(ai, bi);
- }
-
- private static FileHashes t(String text) {
- String[] array = new String[text.length()];
- for (int i = 0; i < text.length(); i++) {
- array[i] = "" + text.charAt(i);
- }
- return FileHashes.create(array);
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/RollingFileHashesTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/RollingFileHashesTest.java
deleted file mode 100644
index 50c3d0eefa0..00000000000
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/tracking/RollingFileHashesTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.plugins.core.issue.tracking;
-
-import org.junit.Test;
-
-import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RollingFileHashesTest {
-
- @Test
- public void test_equals() {
- RollingFileHashes a = RollingFileHashes.create(FileHashes.create(new String[] {md5Hex("line0"), md5Hex("line1"), md5Hex("line2")}), 1);
- RollingFileHashes b = RollingFileHashes.create(FileHashes.create(new String[] {md5Hex("line0"), md5Hex("line1"), md5Hex("line2"), md5Hex("line3")}), 1);
-
- assertThat(a.getHash(1) == b.getHash(1)).isTrue();
- assertThat(a.getHash(2) == b.getHash(2)).isTrue();
- assertThat(a.getHash(3) == b.getHash(3)).isFalse();
-
- RollingFileHashes c = RollingFileHashes.create(FileHashes.create(new String[] {md5Hex("line-1"), md5Hex("line0"), md5Hex("line1"), md5Hex("line2"), md5Hex("line3")}), 1);
- assertThat(a.getHash(1) == c.getHash(2)).isFalse();
- assertThat(a.getHash(2) == c.getHash(3)).isTrue();
- }
-
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v1.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v1.txt
deleted file mode 100644
index 1920333ddb6..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v1.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-package example1;
-
-public class Toto {
-
- public void doSomething() {
- // doSomething
- }
-
- public void doSomethingElse() {
- // doSomethingElse
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v2.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v2.txt
deleted file mode 100644
index 231532452b2..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example1-v2.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-package example1;
-
-public class Toto {
-
- public Toto(){}
-
- public void doSomethingNew() {
- // doSomethingNew
- }
-
- public void doSomethingElseNew() {
- // doSomethingElseNew
- }
-
- public void doSomething() {
- // doSomething
- }
-
- public void doSomethingElse() {
- // doSomethingElse
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v1.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v1.txt
deleted file mode 100644
index a920afe459b..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-package example2;
-
-public class Toto {
- void method1() {
- System.out.println("toto");
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v2.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v2.txt
deleted file mode 100644
index c5c8250cf65..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example2-v2.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-package example2;
-
-public class Toto {
-
- void method2() {
- System.out.println("toto");
- }
-
- void method1() {
- System.out.println("toto");
- }
-
- void method3() {
- System.out.println("toto");
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt
deleted file mode 100644
index facdcbc008c..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-package sample;
-
-public class Sample {
-
- public Sample(int i) {
- int j = i+1; // violation: unused local variable
- }
-
- public boolean avoidUtilityClass() {
- return true;
- }
-
- private String myMethod() { // violation : unused private method
- return "hello";
- }
-}
diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt
deleted file mode 100644
index 91db843fc4d..00000000000
--- a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-package sample;
-
-public class Sample {
-
- public Sample(int i) {
- int j = i+1; // still the same violation: unused local variable
- }
-
- public boolean avoidUtilityClass() {
- return true;
- }
-
- private String myMethod() { // violation "unused private method" is fixed because it's called in newViolation
- return "hello";
- }
-
- public void newViolation() {
- String msg = myMethod(); // new violation : msg is an unused variable
- }
-}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java
index 886104c14a0..01973adef97 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/CreateIssueByInternalKeySensor.java
@@ -19,7 +19,10 @@
*/
package org.sonar.xoo.rule;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
@@ -40,7 +43,9 @@ public class CreateIssueByInternalKeySensor implements Sensor {
@Override
public void execute(SensorContext context) {
- for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) {
+ FileSystem fs = context.fileSystem();
+ FilePredicates p = fs.predicates();
+ for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
createIssues(file, context);
}
}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java
index 3e0b9f48ee5..7e79e2857f6 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OneIssuePerLineSensor.java
@@ -19,7 +19,10 @@
*/
package org.sonar.xoo.rule;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
@@ -43,7 +46,9 @@ public class OneIssuePerLineSensor implements Sensor {
@Override
public void execute(SensorContext context) {
- for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) {
+ FileSystem fs = context.fileSystem();
+ FilePredicates p = fs.predicates();
+ for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) {
createIssues(file, context);
}
}