@@ -30,7 +30,6 @@ 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.api.batch.sensor.test.TestCase; | |||
import org.sonar.xoo.Xoo; | |||
import java.io.File; | |||
@@ -81,13 +80,12 @@ public class CoveragePerTestSensor implements Sensor { | |||
while (lines.hasNext()) { | |||
coveredLines.add(Integer.parseInt(lines.next())); | |||
} | |||
TestCase testCase = context.newTestCase() | |||
.inTestFile(testFile) | |||
.name(testCaseName); | |||
if (testCase == null) { | |||
throw new IllegalStateException("No test case with name " + testCaseName + " on file " + testFile); | |||
} | |||
context.saveCoveragePerTest(testCase, mainFile, coveredLines); | |||
context.newTestCaseCoverage() | |||
.testFile(testFile) | |||
.testName(testCaseName) | |||
.cover(mainFile) | |||
.onLines(coveredLines) | |||
.save(); | |||
} catch (Exception e) { | |||
throw new IllegalStateException("Error processing line " + lineNumber + " of file " + coverPerTest.getAbsolutePath(), e); | |||
} |
@@ -30,7 +30,7 @@ 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.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.xoo.Xoo; | |||
import java.io.File; | |||
@@ -77,11 +77,11 @@ public class TestCaseSensor implements Sensor { | |||
String message = split.next(); | |||
String stack = split.next(); | |||
long duration = Long.parseLong(split.next()); | |||
context.newTestCase() | |||
context.newTestCaseExecution() | |||
.inTestFile(testFile) | |||
.name(name) | |||
.ofType(TestCase.Type.valueOf(type)) | |||
.status(TestCase.Status.valueOf(status)) | |||
.ofType(TestCaseExecution.Type.valueOf(type)) | |||
.status(TestCaseExecution.Status.valueOf(status)) | |||
.message(StringUtils.trimToNull(message)) | |||
.stackTrace(StringUtils.trimToNull(stack)) | |||
.durationInMs(duration) |
@@ -32,8 +32,8 @@ 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.internal.DefaultSensorDescriptor; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -86,19 +86,24 @@ public class CoveragePerTestSensorTest { | |||
final SensorStorage sensorStorage = mock(SensorStorage.class); | |||
when(context.newTestCase()).thenAnswer(new Answer<TestCase>() { | |||
when(context.newTestCaseCoverage()).thenAnswer(new Answer<TestCaseCoverage>() { | |||
@Override | |||
public TestCase answer(InvocationOnMock invocation) throws Throwable { | |||
return new DefaultTestCase(sensorStorage); | |||
public TestCaseCoverage answer(InvocationOnMock invocation) throws Throwable { | |||
return new DefaultTestCaseCoverage(sensorStorage); | |||
} | |||
}); | |||
TestCase test1 = new DefaultTestCase(null).inTestFile(testFile).name("test1"); | |||
TestCase test2 = new DefaultTestCase(null).inTestFile(testFile).name("test2"); | |||
sensor.execute(context); | |||
verify(context).saveCoveragePerTest(test1, inputFile, Arrays.asList(1, 2, 3, 4)); | |||
verify(context).saveCoveragePerTest(test2, inputFile, Arrays.asList(5, 6, 7)); | |||
verify(sensorStorage).store(new DefaultTestCaseCoverage() | |||
.testFile(testFile) | |||
.testName("test1") | |||
.cover(inputFile) | |||
.onLines(Arrays.asList(1, 2, 3, 4))); | |||
verify(sensorStorage).store(new DefaultTestCaseCoverage() | |||
.testFile(testFile) | |||
.testName("test2") | |||
.cover(inputFile) | |||
.onLines(Arrays.asList(5, 6, 7))); | |||
} | |||
} |
@@ -32,8 +32,8 @@ 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.internal.DefaultSensorDescriptor; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -83,24 +83,24 @@ public class TestCaseSensorTest { | |||
final SensorStorage sensorStorage = mock(SensorStorage.class); | |||
when(context.newTestCase()).thenAnswer(new Answer<TestCase>() { | |||
when(context.newTestCaseExecution()).thenAnswer(new Answer<TestCaseExecution>() { | |||
@Override | |||
public TestCase answer(InvocationOnMock invocation) throws Throwable { | |||
return new DefaultTestCase(sensorStorage); | |||
public TestCaseExecution answer(InvocationOnMock invocation) throws Throwable { | |||
return new DefaultTestCaseExecution(sensorStorage); | |||
} | |||
}); | |||
sensor.execute(context); | |||
verify(sensorStorage).store(new DefaultTestCase(null) | |||
verify(sensorStorage).store(new DefaultTestCaseExecution(null) | |||
.inTestFile(testFile) | |||
.name("test1") | |||
.durationInMs(10)); | |||
verify(sensorStorage).store(new DefaultTestCase(null) | |||
verify(sensorStorage).store(new DefaultTestCaseExecution(null) | |||
.inTestFile(testFile) | |||
.name("test2") | |||
.ofType(TestCase.Type.INTEGRATION) | |||
.status(TestCase.Status.ERROR) | |||
.ofType(TestCaseExecution.Type.INTEGRATION) | |||
.status(TestCaseExecution.Status.ERROR) | |||
.message("message") | |||
.stackTrace("stack") | |||
.durationInMs(15)); |
@@ -36,7 +36,8 @@ import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; | |||
import org.sonar.api.batch.sensor.symbol.Symbol; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.platform.PluginMetadata; | |||
@@ -61,8 +62,8 @@ import org.sonar.batch.scan2.MeasureCache; | |||
import org.sonar.batch.scan2.ProjectScanContainer; | |||
import org.sonar.batch.scan2.ScanTaskObserver; | |||
import org.sonar.batch.symbol.SymbolData; | |||
import org.sonar.batch.test.CoveragePerTestCache; | |||
import org.sonar.batch.test.TestCaseCache; | |||
import org.sonar.batch.test.TestCaseCoverageCache; | |||
import org.sonar.batch.test.TestCaseExecutionCache; | |||
import org.sonar.core.plugins.DefaultPluginMetadata; | |||
import org.sonar.core.plugins.RemotePlugin; | |||
import org.sonar.core.source.SnapshotDataTypes; | |||
@@ -233,7 +234,7 @@ public class BatchMediumTester { | |||
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>>(); | |||
private Map<String, Map<String, TestCaseExecution>> testCasesPerFile = new HashMap<String, Map<String, TestCaseExecution>>(); | |||
private Map<String, Map<String, Map<String, List<Integer>>>> coveragePerTest = new HashMap<String, Map<String, Map<String, List<Integer>>>>(); | |||
private Map<String, Map<String, Integer>> dependencies = new HashMap<String, Map<String, Integer>>(); | |||
@@ -258,8 +259,8 @@ public class BatchMediumTester { | |||
} | |||
private void storeCoveragePerTest(ProjectScanContainer container) { | |||
CoveragePerTestCache coveragePerTestCache = container.getComponentByType(CoveragePerTestCache.class); | |||
for (Entry<List<Integer>> entry : coveragePerTestCache.entries()) { | |||
TestCaseCoverageCache testCaseCoverageCache = container.getComponentByType(TestCaseCoverageCache.class); | |||
for (Entry<TestCaseCoverage> entry : testCaseCoverageCache.entries()) { | |||
String testFileKey = entry.key()[0].toString(); | |||
if (!coveragePerTest.containsKey(testFileKey)) { | |||
coveragePerTest.put(testFileKey, new HashMap<String, Map<String, List<Integer>>>()); | |||
@@ -268,16 +269,16 @@ public class BatchMediumTester { | |||
if (!coveragePerTest.get(testFileKey).containsKey(testName)) { | |||
coveragePerTest.get(testFileKey).put(testName, new HashMap<String, List<Integer>>()); | |||
} | |||
coveragePerTest.get(testFileKey).get(testName).put(entry.key()[2].toString(), entry.value()); | |||
coveragePerTest.get(testFileKey).get(testName).put(entry.key()[2].toString(), entry.value().coveredLines()); | |||
} | |||
} | |||
private void storeTestCases(ProjectScanContainer container) { | |||
TestCaseCache testCaseCache = container.getComponentByType(TestCaseCache.class); | |||
for (Entry<TestCase> entry : testCaseCache.entries()) { | |||
TestCaseExecutionCache testCaseCache = container.getComponentByType(TestCaseExecutionCache.class); | |||
for (Entry<TestCaseExecution> entry : testCaseCache.entries()) { | |||
String effectiveKey = entry.key()[0].toString(); | |||
if (!testCasesPerFile.containsKey(effectiveKey)) { | |||
testCasesPerFile.put(effectiveKey, new HashMap<String, TestCase>()); | |||
testCasesPerFile.put(effectiveKey, new HashMap<String, TestCaseExecution>()); | |||
} | |||
testCasesPerFile.get(effectiveKey).put(entry.value().name(), entry.value()); | |||
} | |||
@@ -358,7 +359,7 @@ public class BatchMediumTester { | |||
return duplications.get(((DefaultInputFile) inputFile).key()); | |||
} | |||
public Collection<TestCase> testCasesFor(InputFile inputFile) { | |||
public Collection<TestCaseExecution> testCasesFor(InputFile inputFile) { | |||
String key = ((DefaultInputFile) inputFile).key(); | |||
if (testCasesPerFile.containsKey(key)) { | |||
return testCasesPerFile.get(key).values(); | |||
@@ -367,7 +368,7 @@ public class BatchMediumTester { | |||
} | |||
} | |||
public TestCase testCase(InputFile inputFile, String testCaseName) { | |||
public TestCaseExecution testCase(InputFile inputFile, String testCaseName) { | |||
return testCasesPerFile.get(((DefaultInputFile) inputFile).key()).get(testCaseName); | |||
} | |||
@@ -19,13 +19,11 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import com.google.common.base.Preconditions; | |||
import org.sonar.api.batch.Sensor; | |||
import org.sonar.api.batch.SonarIndex; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
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.InputPath; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
@@ -33,8 +31,9 @@ import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.Issue.Severity; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import org.sonar.api.component.ResourcePerspectives; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.design.Dependency; | |||
@@ -61,8 +60,6 @@ import org.sonar.batch.index.ComponentDataCache; | |||
import org.sonar.batch.scan2.BaseSensorContext; | |||
import org.sonar.core.component.ComponentKeys; | |||
import java.util.List; | |||
/** | |||
* Implements {@link SensorContext} but forward everything to {@link org.sonar.api.batch.SensorContext} for backward compatibility. | |||
* Will be dropped once old {@link Sensor} API is dropped. | |||
@@ -178,8 +175,8 @@ public class SensorContextAdapter extends BaseSensorContext { | |||
} | |||
@Override | |||
public void store(TestCase testCase) { | |||
File testRes = getTestResource(((DefaultTestCase) testCase).testFile()); | |||
public void store(TestCaseExecution testCase) { | |||
File testRes = getTestResource(((DefaultTestCaseExecution) testCase).testFile()); | |||
MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); | |||
if (testPlan != null) { | |||
testPlan | |||
@@ -193,16 +190,15 @@ public class SensorContextAdapter extends BaseSensorContext { | |||
} | |||
@Override | |||
public void saveCoveragePerTest(TestCase testCase, InputFile coveredFile, List<Integer> coveredLines) { | |||
Preconditions.checkArgument(coveredFile.type() == Type.MAIN, "Should be a main file: " + coveredFile); | |||
File testRes = getTestResource(((DefaultTestCase) testCase).testFile()); | |||
File mainRes = getMainResource(coveredFile); | |||
public void store(TestCaseCoverage testCaseCoverage) { | |||
File testRes = getTestResource(testCaseCoverage.testFile()); | |||
File mainRes = getMainResource(testCaseCoverage.coveredFile()); | |||
Testable testAbleFile = perspectives.as(MutableTestable.class, mainRes); | |||
if (testAbleFile != null) { | |||
MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testRes); | |||
if (testPlan != null) { | |||
for (MutableTestCase mutableTestCase : testPlan.testCasesByName(testCase.name())) { | |||
mutableTestCase.setCoverageBlock(testAbleFile, coveredLines); | |||
for (MutableTestCase mutableTestCase : testPlan.testCasesByName(testCaseCoverage.testName())) { | |||
mutableTestCase.setCoverageBlock(testAbleFile, testCaseCoverage.coveredLines()); | |||
} | |||
} else { | |||
throw new IllegalStateException("Unable to get MutableTestPlan perspective from " + testRes); |
@@ -38,8 +38,10 @@ import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.batch.duplication.BlockCache; | |||
import org.sonar.batch.duplication.DefaultTokenBuilder; | |||
@@ -153,8 +155,13 @@ public abstract class BaseSensorContext implements SensorContext, SensorStorage | |||
} | |||
@Override | |||
public TestCase newTestCase() { | |||
return new DefaultTestCase(this); | |||
public TestCaseExecution newTestCaseExecution() { | |||
return new DefaultTestCaseExecution(this); | |||
} | |||
@Override | |||
public TestCaseCoverage newTestCaseCoverage() { | |||
return new DefaultTestCaseCoverage(this); | |||
} | |||
@Override |
@@ -19,14 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.scan2; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Strings; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
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.fs.InputPath; | |||
import org.sonar.api.batch.measure.Metric; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
@@ -36,8 +34,9 @@ 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; | |||
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.measures.CoreMetrics; | |||
import org.sonar.api.rule.RuleKey; | |||
@@ -48,8 +47,8 @@ import org.sonar.batch.duplication.DuplicationCache; | |||
import org.sonar.batch.index.ComponentDataCache; | |||
import org.sonar.batch.issue.IssueFilters; | |||
import org.sonar.batch.scan.SensorContextAdapter; | |||
import org.sonar.batch.test.CoveragePerTestCache; | |||
import org.sonar.batch.test.TestCaseCache; | |||
import org.sonar.batch.test.TestCaseCoverageCache; | |||
import org.sonar.batch.test.TestCaseExecutionCache; | |||
import org.sonar.core.component.ComponentKeys; | |||
import java.io.Serializable; | |||
@@ -89,20 +88,20 @@ public class DefaultSensorContext extends BaseSensorContext { | |||
private final ProjectDefinition def; | |||
private final ActiveRules activeRules; | |||
private final IssueFilters issueFilters; | |||
private final TestCaseCache testCaseCache; | |||
private final CoveragePerTestCache coveragePerTestCache; | |||
private final TestCaseExecutionCache testCaseExecutionCache; | |||
private final TestCaseCoverageCache coveragePerTestCache; | |||
private final DependencyCache dependencyCache; | |||
public DefaultSensorContext(ProjectDefinition def, MeasureCache measureCache, IssueCache issueCache, | |||
Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache, | |||
BlockCache blockCache, DuplicationCache duplicationCache, TestCaseCache testCaseCache, CoveragePerTestCache coveragePerTestCache, DependencyCache dependencyCache) { | |||
BlockCache blockCache, DuplicationCache duplicationCache, TestCaseExecutionCache testCaseCache, TestCaseCoverageCache coveragePerTestCache, DependencyCache dependencyCache) { | |||
super(settings, fs, activeRules, componentDataCache, blockCache, duplicationCache); | |||
this.def = def; | |||
this.measureCache = measureCache; | |||
this.issueCache = issueCache; | |||
this.activeRules = activeRules; | |||
this.issueFilters = issueFilters; | |||
this.testCaseCache = testCaseCache; | |||
this.testCaseExecutionCache = testCaseCache; | |||
this.coveragePerTestCache = coveragePerTestCache; | |||
this.dependencyCache = dependencyCache; | |||
} | |||
@@ -157,18 +156,19 @@ public class DefaultSensorContext extends BaseSensorContext { | |||
} | |||
@Override | |||
public void store(TestCase testCase) { | |||
if (testCaseCache.contains(((DefaultTestCase) testCase).testFile(), testCase.name())) { | |||
throw new IllegalArgumentException("There is already a test case with the same name: " + testCase.name()); | |||
public void store(TestCaseExecution testCaseExecution) { | |||
if (testCaseExecutionCache.contains(((DefaultTestCaseExecution) testCaseExecution).testFile(), testCaseExecution.name())) { | |||
throw new IllegalArgumentException("There is already a test case with the same name: " + testCaseExecution.name()); | |||
} | |||
testCaseCache.put(((DefaultTestCase) testCase).testFile(), testCase); | |||
testCaseExecutionCache.put(((DefaultTestCaseExecution) testCaseExecution).testFile(), testCaseExecution); | |||
} | |||
@Override | |||
public void saveCoveragePerTest(TestCase testCase, InputFile coveredFile, List<Integer> coveredLines) { | |||
Preconditions.checkNotNull(testCase); | |||
Preconditions.checkArgument(coveredFile.type() == Type.MAIN, "Should be a main file: " + coveredFile); | |||
coveragePerTestCache.put(testCase, coveredFile, coveredLines); | |||
public void store(TestCaseCoverage testCaseCoverage) { | |||
if (coveragePerTestCache.getCoverage(testCaseCoverage.testFile(), testCaseCoverage.testName(), testCaseCoverage.coveredFile()) != null) { | |||
throw new IllegalArgumentException("Test coverage already registered for this combination of test file, test name and main file: " + testCaseCoverage); | |||
} | |||
coveragePerTestCache.put(testCaseCoverage); | |||
} | |||
@Override |
@@ -48,8 +48,8 @@ import org.sonar.batch.scan.ProjectSettings; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; | |||
import org.sonar.batch.scan.maven.MavenPluginExecutor; | |||
import org.sonar.batch.test.CoveragePerTestCache; | |||
import org.sonar.batch.test.TestCaseCache; | |||
import org.sonar.batch.test.TestCaseCoverageCache; | |||
import org.sonar.batch.test.TestCaseExecutionCache; | |||
public class ProjectScanContainer extends ComponentContainer { | |||
public ProjectScanContainer(ComponentContainer taskContainer) { | |||
@@ -118,8 +118,8 @@ public class ProjectScanContainer extends ComponentContainer { | |||
DuplicationCache.class, | |||
// Tests | |||
TestCaseCache.class, | |||
CoveragePerTestCache.class, | |||
TestCaseExecutionCache.class, | |||
TestCaseCoverageCache.class, | |||
// Dependencies | |||
DependencyCache.class, |
@@ -0,0 +1,81 @@ | |||
/* | |||
* 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.test; | |||
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.test.internal.DefaultTestCaseCoverage; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
class DefaultTestCaseCoverageValueCoder implements ValueCoder { | |||
private InputPathCache inputPathCache; | |||
public DefaultTestCaseCoverageValueCoder(InputPathCache inputPathCache) { | |||
this.inputPathCache = inputPathCache; | |||
} | |||
@Override | |||
public void put(Value value, Object object, CoderContext context) { | |||
DefaultTestCaseCoverage t = (DefaultTestCaseCoverage) object; | |||
value.putUTF(((DefaultInputFile) t.testFile()).moduleKey()); | |||
value.putUTF(((DefaultInputFile) t.testFile()).relativePath()); | |||
value.putUTF(t.testName()); | |||
value.putUTF(((DefaultInputFile) t.coveredFile()).moduleKey()); | |||
value.putUTF(((DefaultInputFile) t.coveredFile()).relativePath()); | |||
value.put(t.coveredLines().size()); | |||
for (Integer line : t.coveredLines()) { | |||
value.put(line.intValue()); | |||
} | |||
} | |||
@Override | |||
public Object get(Value value, Class clazz, CoderContext context) { | |||
String testModuleKey = value.getString(); | |||
String testRelativePath = value.getString(); | |||
InputFile testFile = inputPathCache.getFile(testModuleKey, testRelativePath); | |||
if (testFile == null) { | |||
throw new IllegalStateException("Unable to load InputFile " + testModuleKey + ":" + testRelativePath); | |||
} | |||
String name = value.getString(); | |||
String mainModuleKey = value.getString(); | |||
String mainRelativePath = value.getString(); | |||
InputFile mainFile = inputPathCache.getFile(mainModuleKey, mainRelativePath); | |||
if (mainFile == null) { | |||
throw new IllegalStateException("Unable to load InputFile " + mainModuleKey + ":" + mainRelativePath); | |||
} | |||
int size = value.getInt(); | |||
List<Integer> lines = new ArrayList<Integer>(size); | |||
for (int i = 0; i < size; i++) { | |||
lines.add(value.getInt()); | |||
} | |||
return new DefaultTestCaseCoverage() | |||
.testFile(testFile) | |||
.testName(name) | |||
.cover(mainFile) | |||
.onLines(lines); | |||
} | |||
} |
@@ -24,23 +24,23 @@ 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.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
import javax.annotation.Nullable; | |||
class DefaultTestCaseValueCoder implements ValueCoder { | |||
class DefaultTestCaseExecutionValueCoder implements ValueCoder { | |||
private InputPathCache inputPathCache; | |||
public DefaultTestCaseValueCoder(InputPathCache inputPathCache) { | |||
public DefaultTestCaseExecutionValueCoder(InputPathCache inputPathCache) { | |||
this.inputPathCache = inputPathCache; | |||
} | |||
@Override | |||
public void put(Value value, Object object, CoderContext context) { | |||
DefaultTestCase t = (DefaultTestCase) object; | |||
DefaultTestCaseExecution t = (DefaultTestCaseExecution) object; | |||
value.putUTF(((DefaultInputFile) t.testFile()).moduleKey()); | |||
value.putUTF(((DefaultInputFile) t.testFile()).relativePath()); | |||
value.putUTF(t.name()); | |||
@@ -72,9 +72,9 @@ class DefaultTestCaseValueCoder implements ValueCoder { | |||
String message = value.getString(); | |||
String stack = value.getString(); | |||
long duration = value.getLong(); | |||
TestCase.Type type = TestCase.Type.values()[value.getInt()]; | |||
TestCase.Status status = TestCase.Status.values()[value.getInt()]; | |||
return new DefaultTestCase() | |||
TestCaseExecution.Type type = TestCaseExecution.Type.values()[value.getInt()]; | |||
TestCaseExecution.Status status = TestCaseExecution.Status.values()[value.getInt()]; | |||
return new DefaultTestCaseExecution() | |||
.inTestFile(testFile) | |||
.ofType(type) | |||
.name(name) |
@@ -23,43 +23,42 @@ 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.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseCoverage; | |||
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; | |||
import java.util.List; | |||
/** | |||
* Cache of coverage per test. This cache is shared amongst all project modules. | |||
*/ | |||
public class CoveragePerTestCache implements BatchComponent { | |||
public class TestCaseCoverageCache implements BatchComponent { | |||
private final Cache<List<Integer>> cache; | |||
private final Cache<TestCaseCoverage> cache; | |||
public CoveragePerTestCache(Caches caches) { | |||
cache = caches.createCache("coveragePerTest"); | |||
public TestCaseCoverageCache(Caches caches, InputPathCache inputPathCache) { | |||
caches.registerValueCoder(DefaultTestCaseCoverage.class, new DefaultTestCaseCoverageValueCoder(inputPathCache)); | |||
cache = caches.createCache("testCaseCoverage"); | |||
} | |||
public Iterable<Entry<List<Integer>>> entries() { | |||
public Iterable<Entry<TestCaseCoverage>> entries() { | |||
return cache.entries(); | |||
} | |||
@CheckForNull | |||
public List<Integer> getCoveredLines(InputFile testFile, String testCaseName, InputFile mainFile) { | |||
public TestCaseCoverage getCoverage(InputFile testFile, String testCaseName, InputFile mainFile) { | |||
Preconditions.checkNotNull(testFile); | |||
Preconditions.checkNotNull(testCaseName); | |||
Preconditions.checkNotNull(mainFile); | |||
return cache.get(((DefaultInputFile) testFile).key(), testCaseName, ((DefaultInputFile) mainFile).key()); | |||
} | |||
public CoveragePerTestCache put(TestCase testCase, InputFile mainFile, List<Integer> coveredLines) { | |||
Preconditions.checkNotNull(testCase); | |||
Preconditions.checkNotNull(mainFile); | |||
Preconditions.checkNotNull(coveredLines); | |||
cache.put(((DefaultInputFile) ((DefaultTestCase) testCase).testFile()).key(), testCase.name(), ((DefaultInputFile) mainFile).key(), coveredLines); | |||
public TestCaseCoverageCache put(TestCaseCoverage coverage) { | |||
Preconditions.checkNotNull(coverage); | |||
cache.put(((DefaultInputFile) coverage.testFile()).key(), coverage.testName(), ((DefaultInputFile) coverage.coveredFile()).key(), coverage); | |||
return this; | |||
} | |||
@@ -23,8 +23,8 @@ 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.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.batch.sensor.test.internal.DefaultTestCaseExecution; | |||
import org.sonar.batch.index.Cache; | |||
import org.sonar.batch.index.Cache.Entry; | |||
import org.sonar.batch.index.Caches; | |||
@@ -35,27 +35,27 @@ import javax.annotation.CheckForNull; | |||
/** | |||
* Cache of all TestCases. This cache is shared amongst all project modules. | |||
*/ | |||
public class TestCaseCache implements BatchComponent { | |||
public class TestCaseExecutionCache implements BatchComponent { | |||
private final Cache<TestCase> cache; | |||
private final Cache<TestCaseExecution> cache; | |||
public TestCaseCache(Caches caches, InputPathCache inputPathCache) { | |||
caches.registerValueCoder(DefaultTestCase.class, new DefaultTestCaseValueCoder(inputPathCache)); | |||
cache = caches.createCache("testCases"); | |||
public TestCaseExecutionCache(Caches caches, InputPathCache inputPathCache) { | |||
caches.registerValueCoder(DefaultTestCaseExecution.class, new DefaultTestCaseExecutionValueCoder(inputPathCache)); | |||
cache = caches.createCache("testCaseExecutions"); | |||
} | |||
public Iterable<Entry<TestCase>> entries() { | |||
public Iterable<Entry<TestCaseExecution>> entries() { | |||
return cache.entries(); | |||
} | |||
@CheckForNull | |||
public TestCase get(InputFile testFile, String testCaseName) { | |||
public TestCaseExecution get(InputFile testFile, String testCaseName) { | |||
Preconditions.checkNotNull(testFile); | |||
Preconditions.checkNotNull(testCaseName); | |||
return cache.get(((DefaultInputFile) testFile).key(), testCaseName); | |||
} | |||
public TestCaseCache put(InputFile testFile, TestCase testCase) { | |||
public TestCaseExecutionCache put(InputFile testFile, TestCaseExecution testCase) { | |||
Preconditions.checkNotNull(testFile); | |||
Preconditions.checkNotNull(testCase); | |||
cache.put(((DefaultInputFile) testFile).key(), testCase.name(), testCase); |
@@ -0,0 +1 @@ | |||
.sonar |
@@ -30,7 +30,8 @@ import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; | |||
import org.sonar.api.batch.sensor.test.TestCase; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import org.sonar.api.config.Settings; | |||
import java.io.Serializable; | |||
@@ -112,21 +113,18 @@ public interface SensorContext { | |||
// ------------ TESTS ------------ | |||
/** | |||
* Create a new test case. | |||
* Don't forget to call {@link TestCase#save()} once all parameters are provided. | |||
* Create a new test case execution report. | |||
* Don't forget to call {@link TestCaseExecution#save()} once all parameters are provided. | |||
* @since 5.0 | |||
*/ | |||
TestCase newTestCase(); | |||
TestCaseExecution newTestCaseExecution(); | |||
/** | |||
* Register coverage of a given test case on another main file. TestCase should have been registered using {@link #testPlanBuilder(InputFile)} | |||
* @param testFile test file containing the test case | |||
* @param testCaseName name of the test case | |||
* @param coveredFile main file that is covered | |||
* @param coveredLines list of covered lines | |||
* Create a new test case coverage report. | |||
* Don't forget to call {@link TestCaseCoverage#save()} once all parameters are provided. | |||
* @since 5.0 | |||
*/ | |||
void saveCoveragePerTest(TestCase testCase, InputFile coveredFile, List<Integer> coveredLines); | |||
TestCaseCoverage newTestCaseCoverage(); | |||
// ------------ DEPENDENCIES ------------ | |||
@@ -22,7 +22,8 @@ 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; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
/** | |||
* Interface for storing data computed by sensors. | |||
@@ -34,8 +35,10 @@ public interface SensorStorage { | |||
void store(Issue issue); | |||
void store(TestCase testCase); | |||
void store(TestCaseExecution testCaseExecution); | |||
void store(Dependency dependency); | |||
void store(TestCaseCoverage testCaseCoverage); | |||
} |
@@ -22,28 +22,26 @@ 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 org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import javax.annotation.Nullable; | |||
public class DefaultDependency implements Dependency { | |||
public class DefaultDependency extends DefaultStorable 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; | |||
super(null); | |||
} | |||
public DefaultDependency(@Nullable SensorStorage storage) { | |||
this.storage = storage; | |||
super(storage); | |||
} | |||
@Override | |||
@@ -68,14 +66,11 @@ public class DefaultDependency implements Dependency { | |||
} | |||
@Override | |||
public void save() { | |||
Preconditions.checkNotNull(this.storage, "No persister on this object"); | |||
Preconditions.checkState(!saved, "This dependency was already saved"); | |||
public void doSave() { | |||
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 | |||
@@ -123,9 +118,4 @@ public class DefaultDependency implements Dependency { | |||
toHashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.sensor.internal; | |||
import com.google.common.base.Preconditions; | |||
import org.apache.commons.lang.builder.ToStringBuilder; | |||
import org.apache.commons.lang.builder.ToStringStyle; | |||
import org.sonar.api.batch.sensor.SensorStorage; | |||
import javax.annotation.Nullable; | |||
public abstract class DefaultStorable { | |||
protected transient final SensorStorage storage; | |||
private transient boolean saved = false; | |||
public DefaultStorable() { | |||
this.storage = null; | |||
} | |||
public DefaultStorable(@Nullable SensorStorage storage) { | |||
this.storage = storage; | |||
} | |||
public final void save() { | |||
Preconditions.checkNotNull(this.storage, "No persister on this object"); | |||
Preconditions.checkState(!saved, "This measure was already saved"); | |||
doSave(); | |||
this.saved = true; | |||
} | |||
protected abstract void doSave(); | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); | |||
} | |||
} |
@@ -21,12 +21,11 @@ package org.sonar.api.batch.sensor.issue.internal; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Strings; | |||
import org.apache.commons.lang.builder.ToStringBuilder; | |||
import org.apache.commons.lang.builder.ToStringStyle; | |||
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.sensor.SensorStorage; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.rule.RuleKey; | |||
@@ -35,7 +34,7 @@ import javax.annotation.Nullable; | |||
import java.util.UUID; | |||
public class DefaultIssue implements Issue { | |||
public class DefaultIssue extends DefaultStorable implements Issue { | |||
private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null"; | |||
private static final String INPUT_FILE_SHOULD_BE_NON_NULL = "InputFile should be non null"; | |||
@@ -49,16 +48,15 @@ public class DefaultIssue implements Issue { | |||
private Integer line; | |||
private Double effortToFix; | |||
private Severity overridenSeverity; | |||
private final SensorStorage storage; | |||
public DefaultIssue() { | |||
super(null); | |||
this.key = UUID.randomUUID().toString(); | |||
this.storage = null; | |||
} | |||
public DefaultIssue(SensorStorage storage) { | |||
super(storage); | |||
this.key = UUID.randomUUID().toString(); | |||
this.storage = storage; | |||
} | |||
@Override | |||
@@ -154,11 +152,9 @@ public class DefaultIssue implements Issue { | |||
} | |||
@Override | |||
public void save() { | |||
Preconditions.checkNotNull(this.storage, "No persister on this object"); | |||
public void doSave() { | |||
Preconditions.checkNotNull(this.ruleKey, "ruleKey is mandatory on issue"); | |||
Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key"); | |||
storage.store(this); | |||
} | |||
@@ -187,8 +183,4 @@ public class DefaultIssue implements Issue { | |||
return key.hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); | |||
} | |||
} |
@@ -22,11 +22,10 @@ package org.sonar.api.batch.sensor.measure.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.measure.Metric; | |||
import org.sonar.api.batch.sensor.SensorStorage; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.measure.Measure; | |||
import javax.annotation.CheckForNull; | |||
@@ -34,22 +33,20 @@ import javax.annotation.Nullable; | |||
import java.io.Serializable; | |||
public class DefaultMeasure<G extends Serializable> implements Measure<G> { | |||
public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G> { | |||
private final SensorStorage storage; | |||
private boolean onProject = false; | |||
private InputFile file; | |||
private Metric<G> metric; | |||
private G value; | |||
private boolean saved = false; | |||
private boolean fromCore = false; | |||
public DefaultMeasure() { | |||
this.storage = null; | |||
super(); | |||
} | |||
public DefaultMeasure(@Nullable SensorStorage storage) { | |||
this.storage = storage; | |||
super(storage); | |||
} | |||
@Override | |||
@@ -101,14 +98,11 @@ public class DefaultMeasure<G extends Serializable> implements Measure<G> { | |||
} | |||
@Override | |||
public void save() { | |||
Preconditions.checkNotNull(this.storage, "No persister on this object"); | |||
Preconditions.checkState(!saved, "This measure was already saved"); | |||
public void doSave() { | |||
Preconditions.checkNotNull(this.value, "Measure value can't be null"); | |||
Preconditions.checkNotNull(this.metric, "Measure metric can't be null"); | |||
Preconditions.checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type " + this.metric.valueType()); | |||
storage.store((Measure<Serializable>) this); | |||
this.saved = true; | |||
} | |||
@Override | |||
@@ -157,9 +151,4 @@ public class DefaultMeasure<G extends Serializable> implements Measure<G> { | |||
toHashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
/* | |||
* 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.test; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import java.util.List; | |||
/** | |||
* Represents line coverage produced by a single test in a test file on a single main file. | |||
* @since 5.0 | |||
*/ | |||
public interface TestCaseCoverage { | |||
/** | |||
* InputFile where this test is located. | |||
*/ | |||
InputFile testFile(); | |||
/** | |||
* Set file where this test is located. Mandatory. | |||
*/ | |||
TestCaseCoverage testFile(InputFile testFile); | |||
/** | |||
* Name of this test case. | |||
*/ | |||
String testName(); | |||
/** | |||
* Set name of this test. Name is mandatory. | |||
*/ | |||
TestCaseCoverage testName(String name); | |||
/** | |||
* InputFile covered by this test. | |||
*/ | |||
InputFile coveredFile(); | |||
/** | |||
* Set file covered by this test. Mandatory. | |||
*/ | |||
TestCaseCoverage cover(InputFile mainFile); | |||
/** | |||
* List of line numbers (1-based) covered by this test. | |||
*/ | |||
List<Integer> coveredLines(); | |||
/** | |||
* Set list of line numbers (1-based) covered by this test. Mandatory. | |||
*/ | |||
TestCaseCoverage onLines(List<Integer> lines); | |||
/** | |||
* Call this method only once when your are done with defining the test case coverage. | |||
*/ | |||
void save(); | |||
} |
@@ -24,10 +24,10 @@ import org.sonar.api.batch.fs.InputFile; | |||
import javax.annotation.Nullable; | |||
/** | |||
* Represents a single test in a test file. | |||
* Represents result of execution of a single test in a test file. | |||
* @since 5.0 | |||
*/ | |||
public interface TestCase { | |||
public interface TestCaseExecution { | |||
/** | |||
* Test execution status. | |||
@@ -55,7 +55,7 @@ public interface TestCase { | |||
/** | |||
* Set file where this test is located. Mandatory. | |||
*/ | |||
TestCase inTestFile(InputFile testFile); | |||
TestCaseExecution inTestFile(InputFile testFile); | |||
/** | |||
* Duration in milliseconds | |||
@@ -65,7 +65,7 @@ public interface TestCase { | |||
/** | |||
* Duration in milliseconds | |||
*/ | |||
TestCase durationInMs(long duration); | |||
TestCaseExecution durationInMs(long duration); | |||
/** | |||
* Name of this test case. | |||
@@ -75,7 +75,7 @@ public interface TestCase { | |||
/** | |||
* Set name of this test. Name is mandatory. | |||
*/ | |||
TestCase name(String name); | |||
TestCaseExecution name(String name); | |||
/** | |||
* Status of execution of the test. | |||
@@ -85,7 +85,7 @@ public interface TestCase { | |||
/** | |||
* Status of execution of the test. | |||
*/ | |||
TestCase status(Status status); | |||
TestCaseExecution status(Status status); | |||
/** | |||
* Message (usually in case of {@link Status#ERROR} or {@link Status#FAILURE}). | |||
@@ -95,7 +95,7 @@ public interface TestCase { | |||
/** | |||
* Message (usually in case of {@link Status#ERROR} or {@link Status#FAILURE}). | |||
*/ | |||
TestCase message(String message); | |||
TestCaseExecution message(String message); | |||
/** | |||
* Type of test. | |||
@@ -105,7 +105,7 @@ public interface TestCase { | |||
/** | |||
* Type of test. | |||
*/ | |||
TestCase ofType(Type type); | |||
TestCaseExecution ofType(Type type); | |||
/** | |||
* Stacktrace (usually in case of {@link Status#ERROR}). | |||
@@ -115,10 +115,10 @@ public interface TestCase { | |||
/** | |||
* Set stacktrace (usually in case of {@link Status#ERROR}). | |||
*/ | |||
TestCase stackTrace(String stackTrace); | |||
TestCaseExecution stackTrace(String stackTrace); | |||
/** | |||
* Call this method only once when your are done with defining the test case. | |||
* Call this method only once when your are done with defining the test case execution. | |||
*/ | |||
void save(); | |||
@@ -0,0 +1,138 @@ | |||
/* | |||
* 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.test.internal; | |||
import com.google.common.base.Preconditions; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.apache.commons.lang.builder.EqualsBuilder; | |||
import org.apache.commons.lang.builder.HashCodeBuilder; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.sensor.SensorStorage; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.test.TestCaseCoverage; | |||
import java.util.Collections; | |||
import java.util.List; | |||
public class DefaultTestCaseCoverage extends DefaultStorable implements TestCaseCoverage { | |||
private InputFile testFile; | |||
private InputFile mainFile; | |||
private String name; | |||
private List<Integer> lines; | |||
public DefaultTestCaseCoverage() { | |||
super(null); | |||
} | |||
public DefaultTestCaseCoverage(SensorStorage storage) { | |||
super(storage); | |||
} | |||
@Override | |||
public InputFile testFile() { | |||
return testFile; | |||
} | |||
@Override | |||
public DefaultTestCaseCoverage testFile(InputFile testFile) { | |||
Preconditions.checkNotNull(testFile, "TestFile cannot be null"); | |||
Preconditions.checkArgument(testFile.type() == InputFile.Type.TEST, "Should be a test file: " + testFile); | |||
this.testFile = testFile; | |||
return this; | |||
} | |||
@Override | |||
public InputFile coveredFile() { | |||
return mainFile; | |||
} | |||
@Override | |||
public TestCaseCoverage cover(InputFile mainFile) { | |||
Preconditions.checkNotNull(mainFile, "InputFile cannot be null"); | |||
Preconditions.checkArgument(mainFile.type() == InputFile.Type.MAIN, "Should be a main file: " + mainFile); | |||
this.mainFile = mainFile; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCaseCoverage testName(String name) { | |||
Preconditions.checkArgument(StringUtils.isNotBlank(name), "Test name is mandatory and should not be blank"); | |||
this.name = name; | |||
return this; | |||
} | |||
@Override | |||
public String testName() { | |||
return name; | |||
} | |||
@Override | |||
public List<Integer> coveredLines() { | |||
return Collections.unmodifiableList(lines); | |||
} | |||
@Override | |||
public TestCaseCoverage onLines(List<Integer> lines) { | |||
Preconditions.checkNotNull(lines, "Lines list cannot be null"); | |||
Preconditions.checkArgument(lines.size() > 0, "No need to register test coverage if no line is covered"); | |||
this.lines = lines; | |||
return this; | |||
} | |||
@Override | |||
public void doSave() { | |||
Preconditions.checkNotNull(testFile, "TestFile is mandatory"); | |||
Preconditions.checkNotNull(mainFile, "MainFile is mandatory"); | |||
Preconditions.checkNotNull(name, "Test name is mandatory"); | |||
Preconditions.checkNotNull(lines, "Lines are mandatory"); | |||
storage.store(this); | |||
} | |||
// Just for unit tests | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (obj == null) { | |||
return false; | |||
} | |||
if (obj == this) { | |||
return true; | |||
} | |||
if (obj.getClass() != getClass()) { | |||
return false; | |||
} | |||
DefaultTestCaseCoverage rhs = (DefaultTestCaseCoverage) obj; | |||
return new EqualsBuilder() | |||
.append(testFile, rhs.testFile) | |||
.append(name, rhs.name) | |||
.append(mainFile, rhs.mainFile) | |||
.append(lines.toArray(), rhs.lines.toArray()) | |||
.isEquals(); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return new HashCodeBuilder(13, 43) | |||
.append(testFile) | |||
.append(name) | |||
.append(mainFile) | |||
.toHashCode(); | |||
} | |||
} |
@@ -23,36 +23,34 @@ import com.google.common.base.Preconditions; | |||
import org.apache.commons.lang.StringUtils; | |||
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.test.TestCase; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
public class DefaultTestCase implements TestCase { | |||
public class DefaultTestCaseExecution extends DefaultStorable implements TestCaseExecution { | |||
private final SensorStorage storage; | |||
private InputFile testFile; | |||
private String name; | |||
private Long duration; | |||
private TestCase.Status status = Status.OK; | |||
private TestCaseExecution.Status status = Status.OK; | |||
private String message; | |||
private TestCase.Type type = Type.UNIT; | |||
private TestCaseExecution.Type type = Type.UNIT; | |||
private String stackTrace; | |||
public DefaultTestCase() { | |||
this.storage = null; | |||
public DefaultTestCaseExecution() { | |||
super(null); | |||
} | |||
public DefaultTestCase(SensorStorage storage) { | |||
this.storage = storage; | |||
public DefaultTestCaseExecution(SensorStorage storage) { | |||
super(storage); | |||
} | |||
@Override | |||
public DefaultTestCase inTestFile(InputFile testFile) { | |||
public DefaultTestCaseExecution inTestFile(InputFile testFile) { | |||
Preconditions.checkNotNull(testFile, "TestFile cannot be null"); | |||
Preconditions.checkArgument(testFile.type() == InputFile.Type.TEST, "Should be a test file: " + testFile); | |||
this.testFile = testFile; | |||
@@ -60,41 +58,41 @@ public class DefaultTestCase implements TestCase { | |||
} | |||
@Override | |||
public DefaultTestCase name(String name) { | |||
public DefaultTestCaseExecution name(String name) { | |||
Preconditions.checkArgument(StringUtils.isNotBlank(name), "Test name is mandatory and should not be blank"); | |||
this.name = name; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCase durationInMs(long duration) { | |||
public DefaultTestCaseExecution durationInMs(long duration) { | |||
Preconditions.checkArgument(duration >= 0, "Test duration must be positive (got: " + duration + ")"); | |||
this.duration = duration; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCase status(TestCase.Status status) { | |||
public DefaultTestCaseExecution status(TestCaseExecution.Status status) { | |||
Preconditions.checkNotNull(status); | |||
this.status = status; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCase message(@Nullable String message) { | |||
public DefaultTestCaseExecution message(@Nullable String message) { | |||
this.message = message; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCase ofType(TestCase.Type type) { | |||
public DefaultTestCaseExecution ofType(TestCaseExecution.Type type) { | |||
Preconditions.checkNotNull(type); | |||
this.type = type; | |||
return this; | |||
} | |||
@Override | |||
public DefaultTestCase stackTrace(@Nullable String stackTrace) { | |||
public DefaultTestCaseExecution stackTrace(@Nullable String stackTrace) { | |||
this.stackTrace = stackTrace; | |||
return this; | |||
} | |||
@@ -138,10 +136,9 @@ public class DefaultTestCase implements TestCase { | |||
} | |||
@Override | |||
public void save() { | |||
Preconditions.checkNotNull(this.storage, "No persister on this object"); | |||
public void doSave() { | |||
Preconditions.checkNotNull(testFile, "TestFile is mandatory"); | |||
Preconditions.checkNotNull(name, "TestFile is mandatory"); | |||
Preconditions.checkNotNull(name, "Test name is mandatory"); | |||
storage.store(this); | |||
} | |||
@@ -157,7 +154,7 @@ public class DefaultTestCase implements TestCase { | |||
if (obj.getClass() != getClass()) { | |||
return false; | |||
} | |||
DefaultTestCase rhs = (DefaultTestCase) obj; | |||
DefaultTestCaseExecution rhs = (DefaultTestCaseExecution) obj; | |||
return new EqualsBuilder() | |||
.append(testFile, rhs.testFile) | |||
.append(name, rhs.name) | |||
@@ -181,18 +178,4 @@ public class DefaultTestCase implements TestCase { | |||
.append(stackTrace) | |||
.toHashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) | |||
.append("file", testFile) | |||
.append("name", name) | |||
.append("duration", duration) | |||
.append("status", status) | |||
.append("message", message) | |||
.append("type", type) | |||
.append("stackTrace", stackTrace) | |||
.toString(); | |||
} | |||
} |
@@ -22,7 +22,7 @@ package org.sonar.api.test; | |||
import javax.annotation.Nullable; | |||
/** | |||
* @deprecated since 5.0 see {@link org.sonar.api.batch.sensor.test.TestCase} | |||
* @deprecated since 5.0 see {@link org.sonar.api.batch.sensor.test.TestCaseExecution} | |||
*/ | |||
@Deprecated | |||
public interface TestCase { |
@@ -24,12 +24,12 @@ import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.sensor.test.TestCase.Status; | |||
import org.sonar.api.batch.sensor.test.TestCase.Type; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution.Status; | |||
import org.sonar.api.batch.sensor.test.TestCaseExecution.Type; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
public class DefaultTestCaseTest { | |||
public class DefaultTestCaseExecutionTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
@@ -38,7 +38,7 @@ public class DefaultTestCaseTest { | |||
@Test | |||
public void testCreation() throws Exception { | |||
DefaultTestCase testCase = new DefaultTestCase(null) | |||
DefaultTestCaseExecution testCase = new DefaultTestCaseExecution(null) | |||
.inTestFile(parent) | |||
.name("myTest") | |||
.durationInMs(1) | |||
@@ -58,7 +58,7 @@ public class DefaultTestCaseTest { | |||
@Test | |||
public void testCreationWithDefaultValues() throws Exception { | |||
DefaultTestCase testCase = new DefaultTestCase(null) | |||
DefaultTestCaseExecution testCase = new DefaultTestCaseExecution(null) | |||
.inTestFile(parent) | |||
.name("myTest"); | |||
@@ -73,7 +73,7 @@ public class DefaultTestCaseTest { | |||
@Test | |||
public void testInvalidDuration() throws Exception { | |||
DefaultTestCase builder = new DefaultTestCase(null) | |||
DefaultTestCaseExecution builder = new DefaultTestCaseExecution(null) | |||
.inTestFile(parent) | |||
.name("myTest"); | |||
@@ -84,7 +84,7 @@ public class DefaultTestCaseTest { | |||
@Test | |||
public void testEqualsHashCodeToString() { | |||
DefaultTestCase testCase1 = new DefaultTestCase(null) | |||
DefaultTestCaseExecution testCase1 = new DefaultTestCaseExecution(null) | |||
.inTestFile(parent) | |||
.name("myTest") | |||
.durationInMs(1) | |||
@@ -92,7 +92,7 @@ public class DefaultTestCaseTest { | |||
.stackTrace("stack") | |||
.status(Status.ERROR) | |||
.ofType(Type.UNIT); | |||
DefaultTestCase testCase1a = new DefaultTestCase(null) | |||
DefaultTestCaseExecution testCase1a = new DefaultTestCaseExecution(null) | |||
.inTestFile(parent) | |||
.name("myTest") | |||
.durationInMs(1) | |||
@@ -100,7 +100,7 @@ public class DefaultTestCaseTest { | |||
.stackTrace("stack") | |||
.status(Status.ERROR) | |||
.ofType(Type.UNIT); | |||
DefaultTestCase testCase2 = new DefaultTestCase(null) | |||
DefaultTestCaseExecution testCase2 = new DefaultTestCaseExecution(null) | |||
.inTestFile(new DefaultInputFile("foo2", "src/Foo.php").setType(InputFile.Type.TEST)) | |||
.name("myTest2") | |||
.durationInMs(2) | |||
@@ -116,7 +116,7 @@ public class DefaultTestCaseTest { | |||
assertThat(testCase1).isNotEqualTo("foo"); | |||
assertThat(testCase1.toString()).isEqualTo( | |||
"DefaultTestCase[file=[moduleKey=foo, relative=src/Foo.php, abs=null],name=myTest,duration=1,status=ERROR,message=message,type=UNIT,stackTrace=stack]"); | |||
"DefaultTestCaseExecution[testFile=[moduleKey=foo, relative=src/Foo.php, abs=null],name=myTest,duration=1,status=ERROR,message=message,type=UNIT,stackTrace=stack]"); | |||
assertThat(testCase1.hashCode()).isEqualTo(testCase1a.hashCode()); | |||
} | |||