aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java2
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java20
-rw-r--r--plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/DependencySensor.java103
-rw-r--r--plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java2
-rw-r--r--plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/DependencySensorTest.java107
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/dependency/DefaultDependencyValueCoder.java68
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java19
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java32
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java15
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java12
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/dependency/DependencyMediumTest.java95
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java8
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java7
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java108
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java9
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java3
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/Dependency.java54
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/DefaultDependency.java131
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/package-info.java (renamed from sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java)25
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/package-info.java21
22 files changed, 776 insertions, 74 deletions
diff --git a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
index 1344179bfb2..56805e5dd7a 100644
--- a/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
+++ b/plugins/sonar-cpd-plugin/src/test/java/org/sonar/plugins/cpd/medium/CpdMediumTest.java
@@ -105,7 +105,7 @@ public class CpdMediumTest {
// 4 measures per file
assertThat(result.measures()).hasSize(8);
- InputFile inputFile = result.inputFiles().get(0);
+ InputFile inputFile = result.inputFile("src/sample1.xoo");
// One clone group
List<DuplicationGroup> duplicationGroups = result.duplicationsFor(inputFile);
assertThat(duplicationGroups).hasSize(1);
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
index d28dc487dec..102aa38dfb1 100644
--- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java
@@ -20,8 +20,21 @@
package org.sonar.xoo;
import org.sonar.api.SonarPlugin;
-import org.sonar.xoo.lang.*;
-import org.sonar.xoo.rule.*;
+import org.sonar.xoo.lang.CoveragePerTestSensor;
+import org.sonar.xoo.lang.DependencySensor;
+import org.sonar.xoo.lang.MeasureSensor;
+import org.sonar.xoo.lang.SymbolReferencesSensor;
+import org.sonar.xoo.lang.SyntaxHighlightingSensor;
+import org.sonar.xoo.lang.TestCaseSensor;
+import org.sonar.xoo.lang.XooTokenizerSensor;
+import org.sonar.xoo.rule.CreateIssueByInternalKeySensor;
+import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor;
+import org.sonar.xoo.rule.OneIssuePerLineSensor;
+import org.sonar.xoo.rule.XooFakeExporter;
+import org.sonar.xoo.rule.XooFakeImporter;
+import org.sonar.xoo.rule.XooFakeImporterWithMessages;
+import org.sonar.xoo.rule.XooQualityProfile;
+import org.sonar.xoo.rule.XooRulesDefinition;
import org.sonar.xoo.scm.XooBlameCommand;
import org.sonar.xoo.scm.XooScmProvider;
@@ -58,11 +71,12 @@ public class XooPlugin extends SonarPlugin {
XooTokenizerSensor.class,
TestCaseSensor.class,
CoveragePerTestSensor.class,
+ DependencySensor.class,
OneIssuePerLineSensor.class,
OneIssueOnDirPerFileSensor.class,
CreateIssueByInternalKeySensor.class
- );
+ );
}
}
diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/DependencySensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/DependencySensor.java
new file mode 100644
index 00000000000..929092da866
--- /dev/null
+++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/DependencySensor.java
@@ -0,0 +1,103 @@
+/*
+ * 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.xoo.lang;
+
+import com.google.common.base.Splitter;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.xoo.Xoo;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Parse files *.xoo.deps
+ */
+public class DependencySensor implements Sensor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(DependencySensor.class);
+
+ private static final String DEPS_EXTENSION = ".deps";
+
+ private void processDependencies(InputFile inputFile, SensorContext context) {
+ File ioFile = inputFile.file();
+ File depsFile = new File(ioFile.getParentFile(), ioFile.getName() + DEPS_EXTENSION);
+ if (depsFile.exists()) {
+ LOG.debug("Processing " + depsFile.getAbsolutePath());
+ try {
+ List<String> lines = FileUtils.readLines(depsFile, context.fileSystem().encoding().name());
+ int lineNumber = 0;
+ for (String line : lines) {
+ lineNumber++;
+ if (StringUtils.isBlank(line) || line.startsWith("#")) {
+ continue;
+ }
+ processLine(depsFile, lineNumber, context, line, inputFile);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ private void processLine(File coverPerTest, int lineNumber, SensorContext context, String line, InputFile file) {
+ try {
+ Iterator<String> split = Splitter.on(":").split(line).iterator();
+ String otherFileRelativePath = split.next();
+ FileSystem fs = context.fileSystem();
+ InputFile otherFile = fs.inputFile(fs.predicates().hasRelativePath(otherFileRelativePath));
+ int weight = Integer.parseInt(split.next());
+ context.newDependency()
+ .from(file)
+ .to(otherFile)
+ .weight(weight)
+ .save();
+ } catch (Exception e) {
+ throw new IllegalStateException("Error processing line " + lineNumber + " of file " + coverPerTest.getAbsolutePath(), e);
+ }
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor
+ .name("Xoo Dependency Sensor")
+ .workOnLanguages(Xoo.KEY)
+ .workOnFileTypes(InputFile.Type.MAIN);
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ FileSystem fs = context.fileSystem();
+ FilePredicates p = fs.predicates();
+ for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(InputFile.Type.MAIN)))) {
+ processDependencies(file, context);
+ }
+ }
+}
diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
index 193f3b95349..d5913f277a8 100644
--- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
+++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java
@@ -27,6 +27,6 @@ public class XooPluginTest {
@Test
public void provide_extensions() {
- assertThat(new XooPlugin().getExtensions()).hasSize(17);
+ assertThat(new XooPlugin().getExtensions()).hasSize(18);
}
}
diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/DependencySensorTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/DependencySensorTest.java
new file mode 100644
index 00000000000..11ed815ac3c
--- /dev/null
+++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/lang/DependencySensorTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.xoo.lang;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorStorage;
+import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
+import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DependencySensorTest {
+
+ private DependencySensor sensor;
+ private SensorContext context = mock(SensorContext.class);
+ private DefaultFileSystem fileSystem;
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ private File baseDir;
+
+ @Before
+ public void prepare() throws IOException {
+ baseDir = temp.newFolder();
+ sensor = new DependencySensor();
+ fileSystem = new DefaultFileSystem();
+ when(context.fileSystem()).thenReturn(fileSystem);
+ }
+
+ @Test
+ public void testDescriptor() {
+ sensor.describe(new DefaultSensorDescriptor());
+ }
+
+ @Test
+ public void testNoExecutionIfNoDepsFile() {
+ DefaultInputFile file = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath()).setLanguage("xoo")
+ .setType(Type.MAIN);
+ fileSystem.add(file);
+ sensor.execute(context);
+ }
+
+ @Test
+ public void testExecution() throws IOException {
+ File deps = new File(baseDir, "src/foo.xoo.deps");
+ FileUtils.write(deps, "src/foo2.xoo:2\nsrc2/foo3.xoo:6\n\n#comment");
+ DefaultInputFile inputFile1 = new DefaultInputFile("foo", "src/foo.xoo").setAbsolutePath(new File(baseDir, "src/foo.xoo").getAbsolutePath()).setLanguage("xoo");
+ DefaultInputFile inputFile2 = new DefaultInputFile("foo", "src/foo2.xoo").setAbsolutePath(new File(baseDir, "src/foo2.xoo").getAbsolutePath()).setLanguage("xoo");
+ DefaultInputFile inputFile3 = new DefaultInputFile("foo", "src2/foo3.xoo").setAbsolutePath(new File(baseDir, "src2/foo3.xoo").getAbsolutePath()).setLanguage("xoo");
+ fileSystem.add(inputFile1);
+ fileSystem.add(inputFile2);
+ fileSystem.add(inputFile3);
+
+ final SensorStorage sensorStorage = mock(SensorStorage.class);
+
+ when(context.newDependency()).thenAnswer(new Answer<Dependency>() {
+ @Override
+ public Dependency answer(InvocationOnMock invocation) throws Throwable {
+ return new DefaultDependency(sensorStorage);
+ }
+ });
+
+ sensor.execute(context);
+
+ verify(sensorStorage).store(new DefaultDependency()
+ .from(inputFile1)
+ .to(inputFile2)
+ .weight(2));
+ verify(sensorStorage).store(new DefaultDependency()
+ .from(inputFile1)
+ .to(inputFile3)
+ .weight(6));
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/DefaultDependencyValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/dependency/DefaultDependencyValueCoder.java
new file mode 100644
index 00000000000..8f01f2c233b
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/dependency/DefaultDependencyValueCoder.java
@@ -0,0 +1,68 @@
+/*
+ * 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.batch.dependency;
+
+import com.persistit.Value;
+import com.persistit.encoding.CoderContext;
+import com.persistit.encoding.ValueCoder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
+import org.sonar.batch.scan.filesystem.InputPathCache;
+
+class DefaultDependencyValueCoder implements ValueCoder {
+
+ private InputPathCache inputPathCache;
+
+ public DefaultDependencyValueCoder(InputPathCache inputPathCache) {
+ this.inputPathCache = inputPathCache;
+ }
+
+ @Override
+ public void put(Value value, Object object, CoderContext context) {
+ DefaultDependency dep = (DefaultDependency) object;
+ value.putUTF(((DefaultInputFile) dep.from()).moduleKey());
+ value.putUTF(((DefaultInputFile) dep.from()).relativePath());
+ value.putUTF(((DefaultInputFile) dep.to()).moduleKey());
+ value.putUTF(((DefaultInputFile) dep.to()).relativePath());
+ value.put(dep.weight());
+ }
+
+ @Override
+ public Object get(Value value, Class clazz, CoderContext context) {
+ String fromModuleKey = value.getString();
+ String fromRelativePath = value.getString();
+ InputFile from = inputPathCache.getFile(fromModuleKey, fromRelativePath);
+ if (from == null) {
+ throw new IllegalStateException("Unable to load InputFile " + fromModuleKey + ":" + fromRelativePath);
+ }
+ String toModuleKey = value.getString();
+ String toRelativePath = value.getString();
+ InputFile to = inputPathCache.getFile(toModuleKey, toRelativePath);
+ if (to == null) {
+ throw new IllegalStateException("Unable to load InputFile " + toModuleKey + ":" + toRelativePath);
+ }
+ int weight = value.getInt();
+ return new DefaultDependency()
+ .from(from)
+ .to(to)
+ .weight(weight);
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java b/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java
index 7a064d520fc..9e3709a5532 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/dependency/DependencyCache.java
@@ -23,41 +23,44 @@ import com.google.common.base.Preconditions;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
import org.sonar.batch.index.Cache;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.index.Caches;
+import org.sonar.batch.scan.filesystem.InputPathCache;
import javax.annotation.CheckForNull;
/**
* Cache of all dependencies. This cache is shared amongst all project modules.
- * module key -> from key -> to key -> OutgoingDependency
+ * module key -> from key -> to key -> Dependency
*/
public class DependencyCache implements BatchComponent {
- private final Cache<OutgoingDependency> cache;
+ private final Cache<Dependency> cache;
- public DependencyCache(Caches caches) {
+ public DependencyCache(Caches caches, InputPathCache inputPathCache) {
+ caches.registerValueCoder(DefaultDependency.class, new DefaultDependencyValueCoder(inputPathCache));
cache = caches.createCache("dependencies");
}
- public Iterable<Entry<OutgoingDependency>> entries() {
+ public Iterable<Entry<Dependency>> entries() {
return cache.entries();
}
@CheckForNull
- public OutgoingDependency get(String moduleKey, InputFile from, InputFile to) {
+ public Dependency get(String moduleKey, InputFile from, InputFile to) {
Preconditions.checkNotNull(moduleKey);
Preconditions.checkNotNull(from);
Preconditions.checkNotNull(to);
return cache.get(moduleKey, ((DefaultInputFile) from).key(), ((DefaultInputFile) to).key());
}
- public DependencyCache put(String moduleKey, InputFile from, OutgoingDependency dependency) {
+ public DependencyCache put(String moduleKey, Dependency dependency) {
Preconditions.checkNotNull(moduleKey);
- Preconditions.checkNotNull(from);
Preconditions.checkNotNull(dependency);
- cache.put(moduleKey, ((DefaultInputFile) from).key(), ((DefaultInputFile) dependency.to()).key(), dependency);
+ cache.put(moduleKey, ((DefaultInputFile) dependency.from()).key(), ((DefaultInputFile) dependency.to()).key(), dependency);
return this;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
index 61a6a062867..596edcdec5f 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
@@ -29,6 +29,7 @@ import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.sensor.dependency.Dependency;
import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.batch.sensor.issue.Issue;
@@ -44,7 +45,6 @@ import org.sonar.batch.bootstrap.TaskProperties;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.dependency.DependencyCache;
-import org.sonar.batch.dependency.OutgoingDependency;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.highlighting.SyntaxHighlightingData;
import org.sonar.batch.highlighting.SyntaxHighlightingRule;
@@ -229,8 +229,8 @@ public class BatchMediumTester {
private List<Issue> issues = new ArrayList<Issue>();
private List<Measure> measures = new ArrayList<Measure>();
private Map<String, List<DuplicationGroup>> duplications = new HashMap<String, List<DuplicationGroup>>();
- private List<InputFile> inputFiles = new ArrayList<InputFile>();
- private List<InputDir> inputDirs = new ArrayList<InputDir>();
+ private Map<String, InputFile> inputFiles = new HashMap<String, InputFile>();
+ private Map<String, InputDir> inputDirs = new HashMap<String, InputDir>();
private Map<InputFile, SyntaxHighlightingData> highlightingPerFile = new HashMap<InputFile, SyntaxHighlightingData>();
private Map<InputFile, SymbolData> symbolTablePerFile = new HashMap<InputFile, SymbolData>();
private Map<String, Map<String, TestCase>> testCasesPerFile = new HashMap<String, Map<String, TestCase>>();
@@ -293,7 +293,7 @@ public class BatchMediumTester {
private void storeComponentData(ProjectScanContainer container) {
ComponentDataCache componentDataCache = container.getComponentByType(ComponentDataCache.class);
- for (InputFile file : inputFiles) {
+ for (InputFile file : inputFiles.values()) {
SyntaxHighlightingData highlighting = componentDataCache.getData(((DefaultInputFile) file).key(), SnapshotDataTypes.SYNTAX_HIGHLIGHTING);
if (highlighting != null) {
highlightingPerFile.put(file, highlighting);
@@ -309,16 +309,16 @@ public class BatchMediumTester {
InputPathCache inputFileCache = container.getComponentByType(InputPathCache.class);
for (InputPath inputPath : inputFileCache.all()) {
if (inputPath instanceof InputFile) {
- inputFiles.add((InputFile) inputPath);
+ inputFiles.put(inputPath.relativePath(), (InputFile) inputPath);
} else {
- inputDirs.add((InputDir) inputPath);
+ inputDirs.put(inputPath.relativePath(), (InputDir) inputPath);
}
}
}
private void storeDependencies(ProjectScanContainer container) {
DependencyCache dependencyCache = container.getComponentByType(DependencyCache.class);
- for (Entry<OutgoingDependency> entry : dependencyCache.entries()) {
+ for (Entry<Dependency> entry : dependencyCache.entries()) {
String fromKey = entry.key()[1].toString();
String toKey = entry.key()[2].toString();
if (!dependencies.containsKey(fromKey)) {
@@ -336,12 +336,22 @@ public class BatchMediumTester {
return measures;
}
- public List<InputFile> inputFiles() {
- return inputFiles;
+ public Collection<InputFile> inputFiles() {
+ return inputFiles.values();
}
- public List<InputDir> inputDirs() {
- return inputDirs;
+ @CheckForNull
+ public InputFile inputFile(String relativePath) {
+ return inputFiles.get(relativePath);
+ }
+
+ public Collection<InputDir> inputDirs() {
+ return inputDirs.values();
+ }
+
+ @CheckForNull
+ public InputDir inputDir(String relativePath) {
+ return inputDirs.get(relativePath);
}
public List<DuplicationGroup> duplicationsFor(InputFile inputFile) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java
index 90c00db0ef5..e482d8b86e8 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdapter.java
@@ -70,6 +70,7 @@ import java.util.List;
*/
public class SensorContextAdapter extends BaseSensorContext {
+ private static final String USES = "USES";
private final org.sonar.api.batch.SensorContext sensorContext;
private final MetricFinder metricFinder;
private final Project project;
@@ -241,11 +242,11 @@ public class SensorContextAdapter extends BaseSensorContext {
}
@Override
- public void saveDependency(InputFile from, InputFile to, int weight) {
- File fromResource = getFile(from);
- File toResource = getFile(to);
+ public void store(org.sonar.api.batch.sensor.dependency.Dependency dep) {
+ File fromResource = getFile(dep.from());
+ File toResource = getFile(dep.to());
if (sonarIndex.getEdge(fromResource, toResource) != null) {
- throw new IllegalStateException("Dependency between " + from + " and " + to + " was already saved.");
+ throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved.");
}
Directory fromParent = fromResource.getParent();
Directory toParent = toResource.getParent();
@@ -255,13 +256,13 @@ public class SensorContextAdapter extends BaseSensorContext {
if (parentDep != null) {
parentDep.setWeight(parentDep.getWeight() + 1);
} else {
- parentDep = new Dependency(fromParent, toParent).setUsage("USES").setWeight(1);
+ parentDep = new Dependency(fromParent, toParent).setUsage(USES).setWeight(1);
parentDep = sensorContext.saveDependency(parentDep);
}
}
sensorContext.saveDependency(new Dependency(fromResource, toResource)
- .setUsage("USES")
- .setWeight(weight)
+ .setUsage(USES)
+ .setWeight(dep.weight())
.setParent(parentDep));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java
index beb62d97251..bb81865c4b6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/BaseSensorContext.java
@@ -26,6 +26,8 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorStorage;
+import org.sonar.api.batch.sensor.dependency.Dependency;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
@@ -155,4 +157,9 @@ public abstract class BaseSensorContext implements SensorContext, SensorStorage
return new DefaultTestCase(this);
}
+ @Override
+ public Dependency newDependency() {
+ return new DefaultDependency(this);
+ }
+
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
index dff662a8f9e..90fc49ca395 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java
@@ -31,6 +31,7 @@ import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.DefaultActiveRule;
+import org.sonar.api.batch.sensor.dependency.Dependency;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
import org.sonar.api.batch.sensor.measure.Measure;
@@ -42,7 +43,6 @@ import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.dependency.DependencyCache;
-import org.sonar.batch.dependency.OutgoingDependency;
import org.sonar.batch.duplication.BlockCache;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.ComponentDataCache;
@@ -172,11 +172,11 @@ public class DefaultSensorContext extends BaseSensorContext {
}
@Override
- public void saveDependency(InputFile from, InputFile to, int weight) {
- Preconditions.checkNotNull(from);
- Preconditions.checkNotNull(to);
- OutgoingDependency dep = new OutgoingDependency(to, weight);
- dependencyCache.put(def.getKey(), from, dep);
+ public void store(Dependency dep) {
+ if (dependencyCache.get(def.getKey(), dep.from(), dep.to()) != null) {
+ throw new IllegalStateException("Dependency between " + dep.from() + " and " + dep.to() + " was already saved.");
+ }
+ dependencyCache.put(def.getKey(), dep);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/dependency/DependencyMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/dependency/DependencyMediumTest.java
new file mode 100644
index 00000000000..a6fe43a1b5c
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/dependency/DependencyMediumTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.batch.mediumtest.dependency;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.FileUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+import org.sonar.batch.mediumtest.BatchMediumTester;
+import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
+import org.sonar.xoo.XooPlugin;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DependencyMediumTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public TestName testName = new TestName();
+
+ public BatchMediumTester tester = BatchMediumTester.builder()
+ .registerPlugin("xoo", new XooPlugin())
+ .addDefaultQProfile("xoo", "Sonar Way")
+ .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor"))
+ .build();
+
+ @Before
+ public void prepare() {
+ tester.start();
+ }
+
+ @After
+ public void stop() {
+ tester.stop();
+ }
+
+ @Test
+ public void populateDependenciesOnTempProject() throws IOException {
+
+ File baseDir = temp.newFolder();
+ File srcDir = new File(baseDir, "src");
+ srcDir.mkdir();
+
+ File xooFile = new File(srcDir, "sample.xoo");
+ File xooFile2 = new File(srcDir, "sample2.xoo");
+ File xooFile3 = new File(srcDir, "foo/sample3.xoo");
+ File xooDepsFile = new File(srcDir, "sample.xoo.deps");
+ FileUtils.write(xooFile, "Sample xoo\ncontent");
+ FileUtils.write(xooFile2, "Sample xoo\ncontent");
+ FileUtils.write(xooFile3, "Sample xoo\ncontent");
+ FileUtils.write(xooDepsFile, "src/sample2.xoo:3\nsrc/foo/sample3.xoo:6");
+
+ TaskResult result = tester.newTask()
+ .properties(ImmutableMap.<String, String>builder()
+ .put("sonar.task", "scan")
+ .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
+ .put("sonar.projectKey", "com.foo.project")
+ .put("sonar.projectName", "Foo Project")
+ .put("sonar.projectVersion", "1.0-SNAPSHOT")
+ .put("sonar.projectDescription", "Description of Foo Project")
+ .put("sonar.sources", "src")
+ .build())
+ .start();
+
+ assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/sample2.xoo"))).isEqualTo(3);
+ assertThat(result.dependencyWeight(result.inputFile("src/sample.xoo"), result.inputFile("src/foo/sample3.xoo"))).isEqualTo(6);
+ }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java
index 19d7aea020a..08ac9d7e3cd 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java
@@ -94,9 +94,9 @@ public class FileSystemMediumTest {
assertThat(result.inputFiles()).hasSize(1);
assertThat(result.inputDirs()).hasSize(1);
- assertThat(result.inputFiles().get(0).type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(result.inputFiles().get(0).relativePath()).isEqualTo("src/sample.xoo");
- assertThat(result.inputDirs().get(0).relativePath()).isEqualTo("src");
+ assertThat(result.inputFile("src/sample.xoo").type()).isEqualTo(InputFile.Type.MAIN);
+ assertThat(result.inputFile("src/sample.xoo").relativePath()).isEqualTo("src/sample.xoo");
+ assertThat(result.inputDir("src").relativePath()).isEqualTo("src");
}
@Test
@@ -115,7 +115,7 @@ public class FileSystemMediumTest {
.start();
assertThat(result.inputFiles()).hasSize(1);
- assertThat(result.inputFiles().get(0).type()).isEqualTo(InputFile.Type.TEST);
+ assertThat(result.inputFile("test/sampleTest.xoo").type()).isEqualTo(InputFile.Type.TEST);
}
/**
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java
index b6ce7fb7d52..93ae29ce062 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java
@@ -19,8 +19,6 @@
*/
package org.sonar.batch.mediumtest.highlighting;
-import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.junit.After;
@@ -30,6 +28,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestName;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.batch.mediumtest.BatchMediumTester;
import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult;
import org.sonar.xoo.XooPlugin;
@@ -87,7 +86,7 @@ public class HighlightingMediumTest {
.build())
.start();
- InputFile file = result.inputFiles().get(0);
+ InputFile file = result.inputFile("src/sample.xoo");
assertThat(result.highlightingTypeFor(file, 0)).containsExactly(TypeOfText.STRING);
assertThat(result.highlightingTypeFor(file, 9)).containsExactly(TypeOfText.STRING);
assertThat(result.highlightingTypeFor(file, 10)).isEmpty();
@@ -126,7 +125,7 @@ public class HighlightingMediumTest {
.start();
System.out.println("Duration: " + (System.currentTimeMillis() - start));
- InputFile file = result.inputFiles().get(0);
+ InputFile file = result.inputFile("src/sample.xoo");
assertThat(result.highlightingTypeFor(file, 0)).containsExactly(TypeOfText.STRING);
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
index 8772d371ba2..10c9f37f47f 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java
@@ -80,7 +80,7 @@ public class SymbolMediumTest {
.build())
.start();
- InputFile file = result.inputFiles().get(0);
+ InputFile file = result.inputFile("src/sample.xoo");
assertThat(result.symbolReferencesFor(file, 7, 10)).containsOnly(7, 27);
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java
index f949f7c544d..df477befe80 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java
@@ -28,16 +28,19 @@ import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
+import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency;
import org.sonar.api.batch.sensor.issue.Issue.Severity;
import org.sonar.api.batch.sensor.issue.internal.DefaultIssue;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
+import org.sonar.api.design.Dependency;
import org.sonar.api.issue.Issuable;
import org.sonar.api.issue.Issue;
import org.sonar.api.measures.CoreMetrics;
@@ -55,6 +58,8 @@ import org.sonar.batch.index.ComponentDataCache;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class SensorContextAdapterTest {
@@ -69,6 +74,7 @@ public class SensorContextAdapterTest {
private Settings settings;
private ResourcePerspectives resourcePerspectives;
private Project project;
+ private SonarIndex sonarIndex;
@Before
public void prepare() {
@@ -83,8 +89,9 @@ public class SensorContextAdapterTest {
ComponentDataCache componentDataCache = mock(ComponentDataCache.class);
BlockCache blockCache = mock(BlockCache.class);
project = new Project("myProject");
+ sonarIndex = mock(SonarIndex.class);
adaptor = new SensorContextAdapter(sensorContext, metricFinder, project,
- resourcePerspectives, settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class), mock(SonarIndex.class));
+ resourcePerspectives, settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class), sonarIndex);
}
@Test
@@ -239,4 +246,103 @@ public class SensorContextAdapterTest {
assertThat(issue.effortToFix()).isEqualTo(10.0);
}
+ @Test
+ public void shouldStoreDependencyInSameFolder() {
+
+ File foo = File.create("src/Foo.java");
+ File bar = File.create("src/Bar.java");
+ when(sensorContext.getResource(foo)).thenReturn(foo);
+ when(sensorContext.getResource(bar)).thenReturn(bar);
+
+ adaptor.store(new DefaultDependency()
+ .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN))
+ .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN))
+ .weight(3));
+
+ ArgumentCaptor<Dependency> argumentCaptor = ArgumentCaptor.forClass(Dependency.class);
+
+ verify(sensorContext).saveDependency(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue().getFrom()).isEqualTo(foo);
+ assertThat(argumentCaptor.getValue().getTo()).isEqualTo(bar);
+ assertThat(argumentCaptor.getValue().getWeight()).isEqualTo(3);
+ assertThat(argumentCaptor.getValue().getUsage()).isEqualTo("USES");
+ }
+
+ @Test
+ public void throw_if_attempt_to_save_same_dep_twice() {
+
+ File foo = File.create("src/Foo.java");
+ File bar = File.create("src/Bar.java");
+ when(sensorContext.getResource(foo)).thenReturn(foo);
+ when(sensorContext.getResource(bar)).thenReturn(bar);
+ when(sonarIndex.getEdge(foo, bar)).thenReturn(new Dependency(foo, bar));
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Dependency between [moduleKey=foo, relative=src/Foo.java, abs=null] and [moduleKey=foo, relative=src/Bar.java, abs=null] was already saved.");
+
+ adaptor.store(new DefaultDependency()
+ .from(new DefaultInputFile("foo", "src/Foo.java").setType(Type.MAIN))
+ .to(new DefaultInputFile("foo", "src/Bar.java").setType(Type.MAIN))
+ .weight(3));
+ }
+
+ @Test
+ public void shouldStoreDependencyInDifferentFolder() {
+
+ File foo = File.create("src1/Foo.java");
+ File bar = File.create("src2/Bar.java");
+ when(sensorContext.getResource(foo)).thenReturn(foo);
+ when(sensorContext.getResource(bar)).thenReturn(bar);
+
+ adaptor.store(new DefaultDependency()
+ .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN))
+ .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN))
+ .weight(3));
+
+ ArgumentCaptor<Dependency> argumentCaptor = ArgumentCaptor.forClass(Dependency.class);
+
+ verify(sensorContext, times(2)).saveDependency(argumentCaptor.capture());
+ assertThat(argumentCaptor.getAllValues()).hasSize(2);
+ Dependency value1 = argumentCaptor.getAllValues().get(0);
+ assertThat(value1.getFrom()).isEqualTo(Directory.create("src1"));
+ assertThat(value1.getTo()).isEqualTo(Directory.create("src2"));
+ assertThat(value1.getWeight()).isEqualTo(1);
+ assertThat(value1.getUsage()).isEqualTo("USES");
+
+ Dependency value2 = argumentCaptor.getAllValues().get(1);
+ assertThat(value2.getFrom()).isEqualTo(foo);
+ assertThat(value2.getTo()).isEqualTo(bar);
+ assertThat(value2.getWeight()).isEqualTo(3);
+ assertThat(value2.getUsage()).isEqualTo("USES");
+ }
+
+ @Test
+ public void shouldIncrementParentWeight() {
+
+ File foo = File.create("src1/Foo.java");
+ File bar = File.create("src2/Bar.java");
+ Directory src1 = Directory.create("src1");
+ Directory src2 = Directory.create("src2");
+ when(sensorContext.getResource(foo)).thenReturn(foo);
+ when(sensorContext.getResource(bar)).thenReturn(bar);
+ Dependency parentDep = new Dependency(src1, src2).setWeight(4);
+ when(sonarIndex.getEdge(src1, src2)).thenReturn(parentDep);
+
+ adaptor.store(new DefaultDependency()
+ .from(new DefaultInputFile("foo", "src1/Foo.java").setType(Type.MAIN))
+ .to(new DefaultInputFile("foo", "src2/Bar.java").setType(Type.MAIN))
+ .weight(3));
+
+ ArgumentCaptor<Dependency> argumentCaptor = ArgumentCaptor.forClass(Dependency.class);
+
+ verify(sensorContext).saveDependency(argumentCaptor.capture());
+
+ assertThat(parentDep.getWeight()).isEqualTo(5);
+
+ Dependency value = argumentCaptor.getValue();
+ assertThat(value.getFrom()).isEqualTo(foo);
+ assertThat(value.getTo()).isEqualTo(bar);
+ assertThat(value.getWeight()).isEqualTo(3);
+ assertThat(value.getUsage()).isEqualTo("USES");
+ }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
index 76cab2f4790..831ea878114 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorContext.java
@@ -22,6 +22,7 @@ package org.sonar.api.batch.sensor;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.sensor.dependency.Dependency;
import org.sonar.api.batch.sensor.duplication.DuplicationBuilder;
import org.sonar.api.batch.sensor.duplication.DuplicationGroup;
import org.sonar.api.batch.sensor.duplication.DuplicationTokenBuilder;
@@ -111,7 +112,7 @@ public interface SensorContext {
// ------------ TESTS ------------
/**
- * Create a new test case for the given test file.
+ * Create a new test case.
* Don't forget to call {@link TestCase#save()} once all parameters are provided.
* @since 5.0
*/
@@ -130,10 +131,10 @@ public interface SensorContext {
// ------------ DEPENDENCIES ------------
/**
- * Declare a dependency between 2 files.
- * @param weight Weight of the dependency
+ * Create a new dependency.
+ * Don't forget to call {@link Dependency#save()} once all parameters are provided.
* @since 5.0
*/
- void saveDependency(InputFile from, InputFile to, int weight);
+ Dependency newDependency();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java
index 8298250523b..7faec27f4c6 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/SensorStorage.java
@@ -19,6 +19,7 @@
*/
package org.sonar.api.batch.sensor;
+import org.sonar.api.batch.sensor.dependency.Dependency;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.test.TestCase;
@@ -35,4 +36,6 @@ public interface SensorStorage {
void store(TestCase testCase);
+ void store(Dependency dependency);
+
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/Dependency.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/Dependency.java
new file mode 100644
index 00000000000..87bd3029fbd
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/Dependency.java
@@ -0,0 +1,54 @@
+/*
+ * 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.api.batch.sensor.dependency;
+
+import com.google.common.annotations.Beta;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 5.0
+ */
+@Beta
+public interface Dependency {
+
+ InputFile from();
+
+ Dependency from(InputFile from);
+
+ InputFile to();
+
+ Dependency to(InputFile to);
+
+ /**
+ * Default weight value is 1.
+ */
+ int weight();
+
+ /**
+ * Set the weight of the dependency.
+ */
+ Dependency weight(int weight);
+
+ /**
+ * Save the dependency.
+ */
+ void save();
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/DefaultDependency.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/DefaultDependency.java
new file mode 100644
index 00000000000..34a91f80756
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/DefaultDependency.java
@@ -0,0 +1,131 @@
+/*
+ * 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.api.batch.sensor.dependency.internal;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorStorage;
+import org.sonar.api.batch.sensor.dependency.Dependency;
+
+import javax.annotation.Nullable;
+
+public class DefaultDependency implements Dependency {
+
+ private final SensorStorage storage;
+ private InputFile from;
+ private InputFile to;
+ private int weight = 1;
+ private boolean saved = false;
+
+ public DefaultDependency() {
+ this.storage = null;
+ }
+
+ public DefaultDependency(@Nullable SensorStorage storage) {
+ this.storage = storage;
+ }
+
+ @Override
+ public Dependency from(InputFile from) {
+ Preconditions.checkNotNull(from, "InputFile should be non null");
+ this.from = from;
+ return this;
+ }
+
+ @Override
+ public Dependency to(InputFile to) {
+ Preconditions.checkNotNull(to, "InputFile should be non null");
+ this.to = to;
+ return this;
+ }
+
+ @Override
+ public Dependency weight(int weight) {
+ Preconditions.checkArgument(weight > 1, "weight should be greater than 1");
+ this.weight = weight;
+ return this;
+ }
+
+ @Override
+ public void save() {
+ Preconditions.checkNotNull(this.storage, "No persister on this object");
+ Preconditions.checkState(!saved, "This dependency was already saved");
+ Preconditions.checkState(!this.from.equals(this.to), "From and To can't be the same inputFile");
+ Preconditions.checkNotNull(this.from, "From inputFile can't be null");
+ Preconditions.checkNotNull(this.to, "To inputFile can't be null");
+ storage.store((Dependency) this);
+ this.saved = true;
+ }
+
+ @Override
+ public InputFile from() {
+ return this.from;
+ }
+
+ @Override
+ public InputFile to() {
+ return this.to;
+ }
+
+ @Override
+ public int weight() {
+ return this.weight;
+ }
+
+ // For testing purpose
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+ DefaultDependency rhs = (DefaultDependency) obj;
+ return new EqualsBuilder()
+ .append(from, rhs.from)
+ .append(to, rhs.to)
+ .append(weight, rhs.weight)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(27, 45).
+ append(from).
+ append(to).
+ append(weight).
+ toHashCode();
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/package-info.java
index 0869ee6cde6..d45dd459268 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/dependency/OutgoingDependency.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/internal/package-info.java
@@ -17,26 +17,5 @@
* 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.batch.dependency;
-
-import org.sonar.api.batch.fs.InputFile;
-
-public class OutgoingDependency {
-
- private final InputFile to;
- private final int weight;
-
- public OutgoingDependency(InputFile to, int weight) {
- this.to = to;
- this.weight = weight;
- }
-
- public InputFile to() {
- return to;
- }
-
- public int weight() {
- return weight;
- }
-
-}
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.api.batch.sensor.dependency.internal;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/package-info.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/package-info.java
new file mode 100644
index 00000000000..e42fabac294
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/dependency/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.api.batch.sensor.dependency;