runtime project(path: ':sonar-plugin-api', configuration: 'shadow')
compileOnly project(path: ':sonar-plugin-api')
- testCompile project(path: ':sonar-scanner-engine')
testCompile 'junit:junit'
testCompile 'org.assertj:assertj-core'
testCompile 'org.mockito:mockito-core'
- testCompile project(':server:sonar-server')
+ testCompile project(':sonar-plugin-api-impl')
}
jar {
import org.sonar.api.Plugin;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.PluginContextImpl;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.PluginContextImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.Version;
import org.sonar.xoo.global.GlobalProjectSensor;
import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.sonar.api.batch.postjob.PostJobContext;
import org.sonar.api.utils.log.LogTester;
-import org.sonar.scanner.postjob.DefaultPostJobDescriptor;
+import org.sonar.api.impl.sensor.DefaultPostJobDescriptor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.MetricFinder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextRange;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.DefaultTextRange;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.DefaultTextRange;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.DefaultTextRange;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.DefaultTextRange;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import org.sonar.xoo.Xoo;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
+import org.sonar.api.impl.sensor.SensorContextTester;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.Version;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
-import org.sonar.scanner.sensor.SensorContextTester;
import org.sonar.xoo.Xoo;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.SonarQubeSide;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.Version;
-import org.sonar.server.rule.RuleDefinitionContext;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.batch.scm.BlameCommand.BlameInput;
import org.sonar.api.batch.scm.BlameCommand.BlameOutput;
import org.sonar.api.batch.scm.BlameLine;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.api.utils.DateUtils;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
import org.sonar.xoo.Xoo;
import static java.util.Collections.singletonList;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.ce.queue.CeTaskSubmit.Component;
import org.sonar.ce.task.CeTask;
import org.sonar.core.util.UuidFactory;
CeTaskSubmit taskSubmit2 = createTaskSubmit("some type");
UserDto userDto1 = db.getDbClient().userDao().selectByUuid(db.getSession(), taskSubmit1.getSubmitterUuid());
-
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
assertThat(tasks).hasSize(2);
assertThat(tasks)
.hasSize(2)
- .extracting(task -> task.getComponent().get().getUuid(),task -> task.getMainComponent().get().getUuid())
+ .extracting(task -> task.getComponent().get().getUuid(), task -> task.getMainComponent().get().getUuid())
.containsOnly(tuple(componentForMainComponentUuid2.getUuid(), componentForMainComponentUuid2.getMainComponentUuid()),
tuple(componentForMainComponentUuid4.getUuid(), componentForMainComponentUuid4.getMainComponentUuid()));
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession()))
}
private static int newComponentIdGenerator = new Random().nextInt(8_999_333);
+
private static Component newComponent(String mainComponentUuid) {
return new Component("uuid_" + newComponentIdGenerator++, mainComponentUuid);
}
compileOnly project(':server:sonar-process')
compileOnly project(':server:sonar-server-common')
compileOnly project(':sonar-plugin-api')
+ compileOnly project(':sonar-plugin-api-impl')
compileOnly project(':sonar-duplications')
testCompile 'com.google.code.findbugs:jsr305'
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.ConfigurationBridge;
+import org.sonar.api.impl.config.ConfigurationBridge;
import org.sonar.db.DbClient;
import org.sonar.db.component.BranchType;
import org.sonar.server.setting.ChildSettings;
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.TempFolder;
-import org.sonar.api.utils.internal.DefaultTempFolder;
import org.sonar.server.platform.ServerFileSystem;
/**
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.junit.rules.ExpectedException;
import org.sonar.api.ce.measure.Component;
import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Duration;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.internal.JUnitTempFolder;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.ce.task.log.CeTaskMessages;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.ce.task.CeTask;
import org.sonar.ce.task.projectanalysis.filemove.ScoreMatrix.ScoreFile;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.issue.Issue;
import org.sonar.api.utils.System2;
import org.sonar.core.issue.DefaultIssue;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderImpl;
import org.sonar.ce.task.projectanalysis.analysis.Organization;
import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.System2;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.rule.RuleKey;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
import org.junit.Test;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.config.PurgeConstants;
import org.sonar.core.config.PurgeProperties;
import org.sonar.db.DbSession;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.MessageException;
import org.sonar.core.config.CorePropertyDefinitions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.JUnitTempFolder;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.internal.JUnitTempFolder;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.Component.Type;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.ZipUtils;
-import org.sonar.api.utils.internal.JUnitTempFolder;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.ce.task.CeTask;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogAndArguments;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarQubeVersion;
import org.sonar.api.config.EmailSettings;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.MetadataLoader;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.profiles.AnnotationProfileParser;
import org.sonar.api.profiles.XMLProfileParser;
import org.sonar.api.profiles.XMLProfileSerializer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import static java.lang.Math.abs;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.apache.commons.io.IOUtils;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.ce.container.ComputeEngineStatus;
import org.sonar.ce.monitoring.CEQueueStatus;
import org.sonar.ce.monitoring.CEQueueStatusImpl;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.CeTaskInterrupter;
import org.junit.Test;
import org.picocontainer.ComponentAdapter;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.ce.notification.ReportAnalysisFailureNotificationExecutionListener;
import org.sonar.ce.task.CeTaskInterrupter;
import org.sonar.core.platform.ComponentContainer;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.api.utils.log.LogAndArguments;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
compile project(':sonar-core')
compile project(':sonar-scanner-protocol')
compile project(path: ':sonar-plugin-api', configuration: 'shadow')
+ compile project(':sonar-plugin-api-impl')
compileOnly 'com.google.code.findbugs:jsr305'
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.junit.AssumptionViolatedException;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.dialect.H2;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.dialect.PostgreSql;
import org.sonar.process.logging.LogbackHelper;
testCompile 'org.mockito:mockito-core'
testCompile project(':sonar-testing-harness')
testCompile project(':server:sonar-db-core').sourceSets.test.output
+ testCompile project(':sonar-plugin-api-impl')
testCompileOnly 'com.google.code.findbugs:jsr305'
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.util.CloseableIterator;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.core.util.stream.MoreCollectors;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.DbTester;
import static com.google.common.collect.FluentIterable.from;
long time = alwaysIncreasingSystem2.now() + 10_000;
insertPending("p1", dto -> {
dto.setCreatedAt(time);
- dto.setUpdatedAt(time+500);
+ dto.setUpdatedAt(time + 500);
dto.setMainComponentUuid("c1");
});
insertPending("p2", dto -> {
long time = alwaysIncreasingSystem2.now() + 10_000;
insertPending("p1", dto -> {
dto.setCreatedAt(time);
- dto.setUpdatedAt(time+500);
+ dto.setUpdatedAt(time + 500);
dto.setMainComponentUuid("c2");
});
insertPending("p2", dto -> {
makeInProgress("w1", alwaysIncreasingSystem2.now(), insertPending("i1", dto -> dto.setMainComponentUuid("c1")));
assertThat(underTest.selectCreationDateOfOldestPendingByMainComponentUuid(db.getSession(), "c1"))
- .isEqualTo(Optional.of(time+2000));
+ .isEqualTo(Optional.of(time + 2000));
}
@Test
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.protobuf.DbProjectBranches;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import static java.util.Arrays.asList;
import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.issue.Issue;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.issue.FieldDiffs;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.DbSession;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
-
public class PurgeCommandsTest {
@Rule
assertThat(dbTester.countRowsOfTable("issue_changes")).isEqualTo(1);
}
-
@Test
public void shouldDeleteAnalyses() {
dbTester.prepareDbUnit(getClass(), "shouldDeleteResource.xml");
assertThat(dbTester.countRowsOfTable("issue_changes")).isEqualTo(1);
}
-
@Test
public void shouldDeleteIssuesAndIssueChanges() {
dbTester.prepareDbUnit(getClass(), "shouldDeleteResource.xml");
import java.util.Optional;
import org.junit.Test;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbSession;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.Pagination;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.Pagination;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Test;
import org.sonar.api.user.UserQuery;
import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.process.ProcessProperties;
import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.CoreDbTester;
import static java.lang.String.format;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.apache.commons.lang.math.RandomUtils;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Date;
import java.util.List;
import javax.annotation.Nullable;
-import org.assertj.core.api.AbstractListAssert;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
"UPDATED_AT", PAST);
}
-}
\ No newline at end of file
+}
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.util.SequenceUuidFactory;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.version.v63.DefaultOrganizationUuidProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import java.sql.SQLException;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.CoreDbTester;
import static java.lang.String.valueOf;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.CoreDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.db.CoreDbTester;
import static java.util.stream.Collectors.toList;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.es.MigrationEsClient;
import java.sql.SQLException;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.CoreDbTester;
import org.sonar.server.platform.db.migration.es.MigrationEsClient;
import org.sonar.server.platform.db.migration.step.DataChange;
compile project(':sonar-markdown')
compile project(':sonar-ws')
- compileOnly project(path: ':sonar-plugin-api')
- compileOnly project(path: ':server:sonar-process')
+ compileOnly project(':sonar-plugin-api')
+ compileOnly project(':server:sonar-process')
compileOnly 'com.google.code.findbugs:jsr305'
testCompile 'org.assertj:assertj-guava'
testCompile 'org.mockito:mockito-core'
testCompile project(':server:sonar-db-testing')
+ testCompile project(':sonar-plugin-api-impl')
}
task testJar(type: Jar) {
package org.sonar.server.component.index;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.sonar.api.config.Settings;
import static java.util.function.Function.identity;
-import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+import static org.sonar.api.impl.config.MultivalueProperty.parseAsCsv;
public class ConfigurationProvider extends ProviderAdapter {
package org.sonar.server.issue.index;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
package org.sonar.server.measure.index;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.TempFolder;
-import org.sonar.api.utils.internal.DefaultTempFolder;
public class TempFolderProvider extends ProviderAdapter {
import org.sonar.api.Plugin;
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;
-import org.sonar.api.internal.PluginContextImpl;
+import org.sonar.api.impl.context.PluginContextImpl;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginInfo;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import java.util.Optional;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.ConfigurationBridge;
+import org.sonar.api.impl.config.ConfigurationBridge;
import static java.util.Objects.requireNonNull;
package org.sonar.server.user.index;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
package org.sonar.server.view.index;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.junit.runner.RunWith;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.config.PropertyDefinition.builder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.newindex.SettingsConfiguration;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import java.util.function.Consumer;
import org.junit.Test;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.IndexType.IndexMainType;
import org.sonar.server.es.newindex.SettingsConfiguration;
import org.sonar.server.es.newindex.TestNewIndex;
*/
package org.sonar.server.es.metadata;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.IndexDefinition;
class MetadataIndexDefinitionBridge implements IndexDefinition {
package org.sonar.server.es.newindex;
import org.elasticsearch.cluster.metadata.IndexMetaData;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.FakeDoc;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexType;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexType;
import org.sonar.server.es.IndexType.IndexMainType;
private MapSettings settings = new MapSettings();
private SettingsConfiguration defaultSettingsConfiguration = newBuilder(settings.asConfig()).build();
-
@Test
@UseDataProvider("indexWithAndWithoutRelations")
public void getRelations_returns_empty_if_no_relation_added(Index index) {
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexType;
package org.sonar.server.issue.index;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.EmailSettings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.platform.Server;
import org.sonar.server.l18n.I18nRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.EmailSettings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.platform.Server;
import org.sonar.server.l18n.I18nRule;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.extension.CoreExtension;
import org.sonar.core.extension.CoreExtensionRepository;
import org.sonar.core.platform.PluginInfo;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.db.Database;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.platform.db.migration.step.MigrationSteps;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.Version;
import static org.assertj.core.api.Assertions.assertThat;
*/
package org.sonar.server.platform;
-import org.sonar.api.SonarEdition;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
+import org.sonar.api.SonarEdition;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.Version;
import org.sonar.db.DbTester;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.config.CorePropertyDefinitions;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
parent.setProperty(randomAlphanumeric(16), new Date(RANDOM.nextInt()));
parent.setProperty(randomAlphanumeric(17), new Date(RANDOM.nextInt()), true);
parent.setProperty(randomAlphanumeric(18), new Date(RANDOM.nextInt()), false);
- parent.setProperty(multipleValuesKey, new String[] { randomAlphanumeric(10), randomAlphanumeric(20) });
+ parent.setProperty(multipleValuesKey, new String[] {randomAlphanumeric(10), randomAlphanumeric(20)});
assertThat(underTest.getProperties()).isEqualTo(parent.getProperties());
}
underTest.set(null, "");
}
-
@Test
public void set_will_throw_NPE_if_value_is_null() {
expectedException.expect(NullPointerException.class);
package org.sonar.server.user.index;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
-import org.sonar.api.SonarEdition;
import org.junit.Rule;
import org.junit.Test;
+import org.sonar.api.SonarEdition;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.Version;
import static org.assertj.core.api.Assertions.assertThat;
package org.sonar.server.view.index;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.sonar.api.SonarEdition;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.Version;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.server.util.OkHttpClientProvider;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
compile project(':sonar-duplications')
runtime project(path: ':sonar-plugin-api', configuration: 'shadow')
compileOnly project(path: ':sonar-plugin-api')
+ compile project(':sonar-plugin-api-impl')
compile project(':sonar-ws')
compileOnly 'com.google.code.findbugs:jsr305'
import org.sonar.api.SonarEdition;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarQubeVersion;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.MetadataLoader;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.Version;
-import org.sonar.api.utils.internal.TempFolderCleaner;
+import org.sonar.server.util.TempFolderCleaner;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.extension.CoreExtensionRepositoryImpl;
import org.sonar.core.extension.CoreExtensionsLoader;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import javax.annotation.Nullable;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.utils.MessageException;
-
-/**
- * Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction} that keeps
- * a context of rule for better error messages. Used only when declaring rules.
- *
- * @see org.sonar.api.server.rule.RulesDefinition
- */
-class DefaultDebtRemediationFunctions implements RulesDefinition.DebtRemediationFunctions {
-
- private final String repoKey;
- private final String key;
-
- DefaultDebtRemediationFunctions(String repoKey, String key) {
- this.repoKey = repoKey;
- this.key = key;
- }
-
- @Override
- public DebtRemediationFunction linear(String gapMultiplier) {
- return create(DefaultDebtRemediationFunction.Type.LINEAR, gapMultiplier, null);
- }
-
- @Override
- public DebtRemediationFunction linearWithOffset(String gapMultiplier, String baseEffort) {
- return create(DefaultDebtRemediationFunction.Type.LINEAR_OFFSET, gapMultiplier, baseEffort);
- }
-
- @Override
- public DebtRemediationFunction constantPerIssue(String baseEffort) {
- return create(DefaultDebtRemediationFunction.Type.CONSTANT_ISSUE, null, baseEffort);
- }
-
- @Override
- public DebtRemediationFunction create(DebtRemediationFunction.Type type, @Nullable String gapMultiplier, @Nullable String baseEffort) {
- try {
- return new DefaultDebtRemediationFunction(type, gapMultiplier, baseEffort);
- } catch (Exception e) {
- throw MessageException.of(String.format("The rule '%s:%s' is invalid : %s ", this.repoKey, this.key, e.getMessage()));
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
-
-public class DefaultNewParam implements RulesDefinition.NewParam {
- private final String key;
- private String name;
- private String description;
- private String defaultValue;
- private RuleParamType type = RuleParamType.STRING;
-
- DefaultNewParam(String key) {
- this.key = this.name = key;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public DefaultNewParam setName(@Nullable String s) {
- // name must never be null.
- this.name = StringUtils.defaultIfBlank(s, key);
- return this;
- }
-
- @Override
- public DefaultNewParam setType(RuleParamType t) {
- this.type = t;
- return this;
- }
-
- @Override
- public DefaultNewParam setDescription(@Nullable String s) {
- this.description = StringUtils.defaultIfBlank(s, null);
- return this;
- }
-
- @Override
- public DefaultNewParam setDefaultValue(@Nullable String s) {
- this.defaultValue = defaultIfEmpty(s, null);
- return this;
- }
-
- public String name() {
- return name;
- }
-
- public String description() {
- return description;
- }
-
- public String defaultValue() {
- return defaultValue;
- }
-
- public RuleParamType type() {
- return type;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-public class DefaultNewRepository implements RulesDefinition.NewRepository {
- private final RuleDefinitionContext context;
- private final String key;
- private final boolean isExternal;
- private final String language;
- private String name;
- private final Map<String, RulesDefinition.NewRule> newRules = new HashMap<>();
-
- DefaultNewRepository(RuleDefinitionContext context, String key, String language, boolean isExternal) {
- this.context = context;
- this.key = key;
- this.name = key;
- this.language = language;
- this.isExternal = isExternal;
- }
-
- @Override
- public boolean isExternal() {
- return isExternal;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- String language() {
- return language;
- }
-
- Map<String, RulesDefinition.NewRule> newRules() {
- return newRules;
- }
-
- String name() {
- return name;
- }
-
- @Override
- public DefaultNewRepository setName(@Nullable String s) {
- if (StringUtils.isNotEmpty(s)) {
- this.name = s;
- }
- return this;
- }
-
- @Override
- public RulesDefinition.NewRule createRule(String ruleKey) {
- checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key);
- RulesDefinition.NewRule newRule = new DefaultNewRule(context.currentPluginKey(), key, ruleKey);
- newRules.put(ruleKey, newRule);
- return newRule;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.NewRule rule(String ruleKey) {
- return newRules.get(ruleKey);
- }
-
- @Override
- public Collection<RulesDefinition.NewRule> rules() {
- return newRules.values();
- }
-
- @Override
- public void done() {
- // note that some validations can be done here, for example for
- // verifying that at least one rule is declared
-
- context.registerRepository(this);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("NewRepository{");
- sb.append("key='").append(key).append('\'');
- sb.append(", language='").append(language).append('\'');
- sb.append('}');
- return sb.toString();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleScope;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RuleTagFormat;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static java.lang.String.format;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.lang.StringUtils.isEmpty;
-import static org.apache.commons.lang.StringUtils.trimToNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-class DefaultNewRule implements RulesDefinition.NewRule {
- private final String pluginKey;
- private final String repoKey;
- private final String key;
- private RuleType type;
- private String name;
- private String htmlDescription;
- private String markdownDescription;
- private String internalKey;
- private String severity = Severity.MAJOR;
- private boolean template;
- private RuleStatus status = RuleStatus.defaultStatus();
- private DebtRemediationFunction debtRemediationFunction;
- private String gapDescription;
- private final Set<String> tags = new TreeSet<>();
- private final Set<String> securityStandards = new TreeSet<>();
- private final Map<String, RulesDefinition.NewParam> paramsByKey = new HashMap<>();
- private final RulesDefinition.DebtRemediationFunctions functions;
- private boolean activatedByDefault;
- private RuleScope scope;
- private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>();
-
- DefaultNewRule(@Nullable String pluginKey, String repoKey, String key) {
- this.pluginKey = pluginKey;
- this.repoKey = repoKey;
- this.key = key;
- this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
- }
-
- @Override
- public String key() {
- return this.key;
- }
-
- @CheckForNull
- @Override
- public RuleScope scope() {
- return this.scope;
- }
-
- @Override
- public DefaultNewRule setScope(RuleScope scope) {
- this.scope = scope;
- return this;
- }
-
- @Override
- public DefaultNewRule setName(String s) {
- this.name = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule setTemplate(boolean template) {
- this.template = template;
- return this;
- }
-
- @Override
- public DefaultNewRule setActivatedByDefault(boolean activatedByDefault) {
- this.activatedByDefault = activatedByDefault;
- return this;
- }
-
- @Override
- public DefaultNewRule setSeverity(String s) {
- checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s);
- this.severity = s;
- return this;
- }
-
- @Override
- public DefaultNewRule setType(RuleType t) {
- this.type = t;
- return this;
- }
-
- @Override
- public DefaultNewRule setHtmlDescription(@Nullable String s) {
- checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this);
- this.htmlDescription = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule setHtmlDescription(@Nullable URL classpathUrl) {
- if (classpathUrl != null) {
- try {
- setHtmlDescription(IOUtils.toString(classpathUrl, UTF_8));
- } catch (IOException e) {
- throw new IllegalStateException("Fail to read: " + classpathUrl, e);
- }
- } else {
- this.htmlDescription = null;
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setMarkdownDescription(@Nullable String s) {
- checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this);
- this.markdownDescription = trimToNull(s);
- return this;
- }
-
- @Override
- public DefaultNewRule setMarkdownDescription(@Nullable URL classpathUrl) {
- if (classpathUrl != null) {
- try {
- setMarkdownDescription(IOUtils.toString(classpathUrl, UTF_8));
- } catch (IOException e) {
- throw new IllegalStateException("Fail to read: " + classpathUrl, e);
- }
- } else {
- this.markdownDescription = null;
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setStatus(RuleStatus status) {
- checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this);
- this.status = status;
- return this;
- }
-
- @Override
- public DefaultNewRule setDebtSubCharacteristic(@Nullable String s) {
- return this;
- }
-
- @Override
- public RulesDefinition.DebtRemediationFunctions debtRemediationFunctions() {
- return functions;
- }
-
- @Override
- public DefaultNewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) {
- this.debtRemediationFunction = fn;
- return this;
- }
-
- @Deprecated
- @Override
- public DefaultNewRule setEffortToFixDescription(@Nullable String s) {
- return setGapDescription(s);
- }
-
- @Override
- public DefaultNewRule setGapDescription(@Nullable String s) {
- this.gapDescription = s;
- return this;
- }
-
- @Override
- public RulesDefinition.NewParam createParam(String paramKey) {
- checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this);
- DefaultNewParam param = new DefaultNewParam(paramKey);
- paramsByKey.put(paramKey, param);
- return param;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.NewParam param(String paramKey) {
- return paramsByKey.get(paramKey);
- }
-
- @Override
- public Collection<RulesDefinition.NewParam> params() {
- return paramsByKey.values();
- }
-
- @Override
- public DefaultNewRule addTags(String... list) {
- for (String tag : list) {
- RuleTagFormat.validate(tag);
- tags.add(tag);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setTags(String... list) {
- tags.clear();
- addTags(list);
- return this;
- }
-
- @Override
- public DefaultNewRule addOwaspTop10(RulesDefinition.OwaspTop10... standards) {
- for (RulesDefinition.OwaspTop10 owaspTop10 : standards) {
- String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH);
- securityStandards.add(standard);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule addCwe(int... nums) {
- for (int num : nums) {
- String standard = "cwe:" + num;
- securityStandards.add(standard);
- }
- return this;
- }
-
- @Override
- public DefaultNewRule setInternalKey(@Nullable String s) {
- this.internalKey = s;
- return this;
- }
-
- void validate() {
- if (isEmpty(name)) {
- throw new IllegalStateException(format("Name of rule %s is empty", this));
- }
- if (isEmpty(htmlDescription) && isEmpty(markdownDescription)) {
- throw new IllegalStateException(format("One of HTML description or Markdown description must be defined for rule %s", this));
- }
- }
-
- @Override
- public DefaultNewRule addDeprecatedRuleKey(String repository, String key) {
- deprecatedRuleKeys.add(RuleKey.of(repository, key));
- return this;
- }
-
- String pluginKey() {
- return pluginKey;
- }
-
- String repoKey() {
- return repoKey;
- }
-
- RuleType type() {
- return type;
- }
-
- String name() {
- return name;
- }
-
- String htmlDescription() {
- return htmlDescription;
- }
-
- String markdownDescription() {
- return markdownDescription;
- }
-
- @CheckForNull
- String internalKey() {
- return internalKey;
- }
-
- String severity() {
- return severity;
- }
-
- boolean template() {
- return template;
- }
-
- RuleStatus status() {
- return status;
- }
-
- DebtRemediationFunction debtRemediationFunction() {
- return debtRemediationFunction;
- }
-
- String gapDescription() {
- return gapDescription;
- }
-
- Set<String> tags() {
- return tags;
- }
-
- Set<String> securityStandards() {
- return securityStandards;
- }
-
- Map<String, RulesDefinition.NewParam> paramsByKey() {
- return paramsByKey;
- }
-
- boolean activatedByDefault() {
- return activatedByDefault;
- }
-
- Set<RuleKey> deprecatedRuleKeys() {
- return deprecatedRuleKeys;
- }
-
- @Override
- public String toString() {
- return format("[repository=%s, key=%s]", repoKey, key);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.server.rule.RuleParamType;
-import org.sonar.api.server.rule.RulesDefinition;
-
-@Immutable
-public class DefaultParam implements RulesDefinition.Param {
- private final String key;
- private final String name;
- private final String description;
- private final String defaultValue;
- private final RuleParamType type;
-
- DefaultParam(DefaultNewParam newParam) {
- this.key = newParam.key();
- this.name = newParam.name();
- this.description = newParam.description();
- this.defaultValue = newParam.defaultValue();
- this.type = newParam.type();
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- @Nullable
- public String description() {
- return description;
- }
-
- @Override
- @Nullable
- public String defaultValue() {
- return defaultValue;
- }
-
- @Override
- public RuleParamType type() {
- return type;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- RulesDefinition.Param that = (RulesDefinition.Param) o;
- return key.equals(that.key());
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.utils.log.Loggers;
-
-import static java.lang.String.format;
-import static java.util.Collections.unmodifiableList;
-import static java.util.Collections.unmodifiableMap;
-
-@Immutable
-class DefaultRepository implements RulesDefinition.Repository {
- private final String key;
- private final String language;
- private final String name;
- private final boolean isExternal;
- private final Map<String, RulesDefinition.Rule> rulesByKey;
-
- DefaultRepository(DefaultNewRepository newRepository, @Nullable RulesDefinition.Repository mergeInto) {
- this.key = newRepository.key();
- this.language = newRepository.language();
- this.isExternal = newRepository.isExternal();
- Map<String, RulesDefinition.Rule> ruleBuilder = new HashMap<>();
- if (mergeInto != null) {
- if (!StringUtils.equals(newRepository.language(), mergeInto.language()) || !StringUtils.equals(newRepository.key(), mergeInto.key())) {
- throw new IllegalArgumentException(format("Bug - language and key of the repositories to be merged should be the sames: %s and %s", newRepository, mergeInto));
- }
- this.name = StringUtils.defaultIfBlank(mergeInto.name(), newRepository.name());
- for (RulesDefinition.Rule rule : mergeInto.rules()) {
- if (!newRepository.key().startsWith("common-") && ruleBuilder.containsKey(rule.key())) {
- Loggers.get(getClass()).warn("The rule '{}' of repository '{}' is declared several times", rule.key(), mergeInto.key());
- }
- ruleBuilder.put(rule.key(), rule);
- }
- } else {
- this.name = newRepository.name();
- }
- for (RulesDefinition.NewRule newRule : newRepository.newRules().values()) {
- DefaultNewRule defaultNewRule = (DefaultNewRule) newRule;
- defaultNewRule.validate();
- ruleBuilder.put(newRule.key(), new DefaultRule(this, defaultNewRule));
- }
- this.rulesByKey = unmodifiableMap(ruleBuilder);
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String language() {
- return language;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- public boolean isExternal() {
- return isExternal;
- }
-
- @Override
- @CheckForNull
- public RulesDefinition.Rule rule(String ruleKey) {
- return rulesByKey.get(ruleKey);
- }
-
- @Override
- public List<RulesDefinition.Rule> rules() {
- return unmodifiableList(new ArrayList<>(rulesByKey.values()));
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultRepository that = (DefaultRepository) o;
- return key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("Repository{");
- sb.append("key='").append(key).append('\'');
- sb.append(", language='").append(language).append('\'');
- sb.append('}');
- return sb.toString();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleScope;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.RuleType;
-import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.api.server.rule.RuleTagsToTypeConverter;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static java.lang.String.format;
-import static java.util.Collections.unmodifiableList;
-
-@Immutable
-public class DefaultRule implements RulesDefinition.Rule {
- private final String pluginKey;
- private final RulesDefinition.Repository repository;
- private final String repoKey;
- private final String key;
- private final String name;
- private final RuleType type;
- private final String htmlDescription;
- private final String markdownDescription;
- private final String internalKey;
- private final String severity;
- private final boolean template;
- private final DebtRemediationFunction debtRemediationFunction;
- private final String gapDescription;
- private final Set<String> tags;
- private final Set<String> securityStandards;
- private final Map<String, RulesDefinition.Param> params;
- private final RuleStatus status;
- private final boolean activatedByDefault;
- private final RuleScope scope;
- private final Set<RuleKey> deprecatedRuleKeys;
-
- DefaultRule(DefaultRepository repository, DefaultNewRule newRule) {
- this.pluginKey = newRule.pluginKey();
- this.repository = repository;
- this.repoKey = newRule.repoKey();
- this.key = newRule.key();
- this.name = newRule.name();
- this.htmlDescription = newRule.htmlDescription();
- this.markdownDescription = newRule.markdownDescription();
- this.internalKey = newRule.internalKey();
- this.severity = newRule.severity();
- this.template = newRule.template();
- this.status = newRule.status();
- this.debtRemediationFunction = newRule.debtRemediationFunction();
- this.gapDescription = newRule.gapDescription();
- this.scope = newRule.scope() == null ? RuleScope.MAIN : newRule.scope();
- this.type = newRule.type() == null ? RuleTagsToTypeConverter.convert(newRule.tags()) : newRule.type();
- Set<String> tagsBuilder = new TreeSet<>(newRule.tags());
- tagsBuilder.removeAll(RuleTagsToTypeConverter.RESERVED_TAGS);
- this.tags = Collections.unmodifiableSet(tagsBuilder);
- this.securityStandards = Collections.unmodifiableSet(new TreeSet<>(newRule.securityStandards()));
- Map<String, RulesDefinition.Param> paramsBuilder = new HashMap<>();
- for (RulesDefinition.NewParam newParam : newRule.paramsByKey().values()) {
- paramsBuilder.put(newParam.key(), new DefaultParam((DefaultNewParam) newParam));
- }
- this.params = Collections.unmodifiableMap(paramsBuilder);
- this.activatedByDefault = newRule.activatedByDefault();
- this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys()));
- }
-
- public RulesDefinition.Repository repository() {
- return repository;
- }
-
- @Override
- @CheckForNull
- public String pluginKey() {
- return pluginKey;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- public RuleScope scope() {
- return scope;
- }
-
- @Override
- public RuleType type() {
- return type;
- }
-
- @Override
- public String severity() {
- return severity;
- }
-
- @Override
- @CheckForNull
- public String htmlDescription() {
- return htmlDescription;
- }
-
- @Override
- @CheckForNull
- public String markdownDescription() {
- return markdownDescription;
- }
-
- @Override
- public boolean template() {
- return template;
- }
-
- @Override
- public boolean activatedByDefault() {
- return activatedByDefault;
- }
-
- @Override
- public RuleStatus status() {
- return status;
- }
-
- @CheckForNull
- @Deprecated
- @Override
- public String debtSubCharacteristic() {
- return null;
- }
-
- @CheckForNull
- @Override
- public DebtRemediationFunction debtRemediationFunction() {
- return debtRemediationFunction;
- }
-
- @Deprecated
- @CheckForNull
- @Override
- public String effortToFixDescription() {
- return gapDescription();
- }
-
- @CheckForNull
- @Override
- public String gapDescription() {
- return gapDescription;
- }
-
- @CheckForNull
- @Override
- public RulesDefinition.Param param(String key) {
- return params.get(key);
- }
-
- @Override
- public List<RulesDefinition.Param> params() {
- return unmodifiableList(new ArrayList<>(params.values()));
- }
-
- @Override
- public Set<String> tags() {
- return tags;
- }
-
- @Override
- public Set<String> securityStandards() {
- return securityStandards;
- }
-
- @Override
- public Set<RuleKey> deprecatedRuleKeys() {
- return deprecatedRuleKeys;
- }
-
- @CheckForNull
- @Override
- public String internalKey() {
- return internalKey;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultRule other = (DefaultRule) o;
- return key.equals(other.key) && repoKey.equals(other.repoKey);
- }
-
- @Override
- public int hashCode() {
- int result = repoKey.hashCode();
- result = 31 * result + key.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return format("[repository=%s, key=%s]", repoKey, key);
- }
-}
-
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.rule;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.rule.RulesDefinition;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.unmodifiableList;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class RuleDefinitionContext implements RulesDefinition.Context {
- private final Map<String, RulesDefinition.Repository> repositoriesByKey = new HashMap<>();
- private String currentPluginKey;
-
- @Override
- public RulesDefinition.NewRepository createRepository(String key, String language) {
- return new DefaultNewRepository(this, key, language, false);
- }
-
- @Override
- public RulesDefinition.NewRepository createExternalRepository(String engineId, String language) {
- return new DefaultNewRepository(this, RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, language, true);
- }
-
- @Override
- @Deprecated
- public RulesDefinition.NewRepository extendRepository(String key, String language) {
- return createRepository(key, language);
- }
-
- @Override
- @CheckForNull
- public RulesDefinition.Repository repository(String key) {
- return repositoriesByKey.get(key);
- }
-
- @Override
- public List<RulesDefinition.Repository> repositories() {
- return unmodifiableList(new ArrayList<>(repositoriesByKey.values()));
- }
-
- @Override
- @Deprecated
- public List<RulesDefinition.ExtendedRepository> extendedRepositories(String repositoryKey) {
- return emptyList();
- }
-
- @Override
- @Deprecated
- public List<RulesDefinition.ExtendedRepository> extendedRepositories() {
- return emptyList();
- }
-
- void registerRepository(DefaultNewRepository newRepository) {
- RulesDefinition.Repository existing = repositoriesByKey.get(newRepository.key());
- if (existing != null) {
- String existingLanguage = existing.language();
- checkState(existingLanguage.equals(newRepository.language()),
- "The rule repository '%s' must not be defined for two different languages: %s and %s",
- newRepository.key(), existingLanguage, newRepository.language());
- }
- repositoriesByKey.put(newRepository.key(), new DefaultRepository(newRepository, existing));
- }
-
- public String currentPluginKey() {
- return currentPluginKey;
- }
-
- @Override
- public void setCurrentPluginKey(@Nullable String pluginKey) {
- this.currentPluginKey = pluginKey;
- }
-}
package org.sonar.server.rule;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import org.sonar.server.plugins.ServerPluginRepository;
/**
*/
package org.sonar.server.user.ws;
+import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import org.sonar.api.internal.google.common.base.Preconditions;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.util;
+
+import org.sonar.api.Startable;
+import org.sonar.api.impl.utils.DefaultTempFolder;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.TempFolder;
+
+@ServerSide
+public class TempFolderCleaner implements Startable {
+
+ private TempFolder defaultTempFolder;
+
+ public TempFolderCleaner(TempFolder defaultTempFolder) {
+ this.defaultTempFolder = defaultTempFolder;
+ }
+
+ /**
+ * This method should not be renamed. It follows the naming convention
+ * defined by IoC container.
+ */
+ @Override
+ public void start() {
+ // Nothing to do
+ }
+
+ /**
+ * This method should not be renamed. It follows the naming convention
+ * defined by IoC container.
+ */
+ @Override
+ public void stop() {
+ ((DefaultTempFolder) defaultTempFolder).clean();
+ }
+}
import java.util.Map;
import java.util.Optional;
import org.sonar.api.server.ws.LocalConnector;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.ValidatingRequest;
public class LocalRequestAdapter extends ValidatingRequest {
import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.servlet.http.HttpServletRequest;
-import org.sonar.api.server.ws.internal.PartImpl;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.PartImpl;
+import org.sonar.api.impl.ws.ValidatingRequest;
import org.sonar.api.utils.log.Loggers;
import org.sonarqube.ws.MediaTypes;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.ValidatingRequest;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.text.JsonWriter;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.process.sharedmemoryfile.DefaultProcessCommands;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.security.Authenticator;
import org.sonar.api.security.ExternalGroupsProvider;
import org.sonar.api.security.ExternalUsersProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDto;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserTokenDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.server.authentication.UserIdentity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.alm.AlmAppInstallDto;
import org.sonar.db.component.ResourceTypesRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.server.authentication.UserIdentity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.authentication.BaseIdentityProvider;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.authentication.BasicAuthentication;
import org.sonar.server.authentication.JwtHttpHandler;
import org.sonar.server.authentication.event.AuthenticationException;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric.Level;
import org.sonar.api.server.ws.WebService;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.Metric.Level;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.Metric;
import org.sonar.db.DbTester;
import org.sonar.server.tester.UserSessionRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.web.UserRole;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.process.sharedmemoryfile.DefaultProcessCommands;
import org.sonar.process.ProcessEntryPoint;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeQueueImpl;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.server.es.IndexType.IndexMainType;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.metadata.MetadataIndex;
import org.sonar.server.es.metadata.MetadataIndexImpl;
import org.sonar.server.es.newindex.FakeIndexDefinition;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.server.platform.db.migration.es.MigrationEsClient;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.db.DbSession;
import java.util.stream.Collectors;
import org.junit.Test;
import org.picocontainer.ComponentAdapter;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.System2;
import org.sonar.core.platform.ComponentContainer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.process.NetworkUtils;
import org.sonar.process.cluster.health.NodeDetails;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.DefaultIssueComment;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.junit.rules.ExpectedException;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.es.EsTester;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.junit.rules.ExpectedException;
import org.sonar.api.issue.Issue;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchType;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.RuleKey;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.WebService;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleType;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Durations;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.measure.custom.CustomMeasureDto;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Qualifiers;
import org.mockito.Mockito;
import org.mockito.verification.Timeout;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.Notification;
import static java.util.Collections.singleton;
*/
package org.sonar.server.notification;
-import com.google.common.collect.Sets;
-import java.util.Arrays;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.notifications.NotificationChannel;
import org.sonar.db.DbClient;
-import org.sonar.db.property.PropertiesDao;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
package org.sonar.server.notification.ws;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.NotificationChannel;
import org.sonar.server.issue.notification.FPOrWontFixNotificationHandler;
import org.sonar.server.issue.notification.MyNewIssuesNotificationHandler;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.core.permission.GlobalPermissions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.util.UuidFactoryFast;
package org.sonar.server.organization.ws;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
*/
package org.sonar.server.permission.index;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.es.Index;
import org.sonar.server.es.IndexDefinition;
import org.sonar.server.es.IndexType;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ResourceTypesRule;
import javax.annotation.Nullable;
import org.junit.Test;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
package org.sonar.server.platform.db;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import static org.mockito.Mockito.mock;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.process.NetworkUtilsImpl;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import static org.apache.commons.lang.StringUtils.repeat;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.security.SecurityRealm;
import org.sonar.api.utils.log.LoggerLevel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.picocontainer.ComponentAdapter;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.server.platform.WebServer;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.security.SecurityRealm;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.platform.OfficialDistribution;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ServerId;
import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.Uuids;
import org.junit.runner.RunWith;
import org.sonar.api.CoreProperties;
import org.sonar.api.SonarQubeSide;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.Version;
import org.sonar.core.platform.ServerId;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.stubbing.Answer;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.server.platform.OfficialDistribution;
import org.sonar.server.platform.Platform;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.picocontainer.ComponentAdapter;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.server.platform.WebServer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.PluginInfo;
import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.UriReader;
import org.sonar.process.ProcessProperties;
package org.sonar.server.project.ws;
import org.junit.Test;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.process.ProcessProperties;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.utils.System2;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbSession;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQualityProfile;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.assertj.core.groups.Tuple;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.notifications.Notification;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
-import org.sonar.api.utils.internal.JUnitTempFolder;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.profiles.ProfileExporter;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.QProfileDto;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbSession;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleKey;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.PropertyType;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
import org.sonar.db.qualityprofile.OrgActiveRuleDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Language;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.util.UuidFactoryFast;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileChangeDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.JUnitTempFolder;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.JUnitTempFolder;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.internal.SimpleGetRequest;
+import org.sonar.api.impl.ws.SimpleGetRequest;
import org.sonar.server.ws.WsTester;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleQuery;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import org.sonar.server.debt.DebtModelPluginRepository;
import org.sonar.server.debt.DebtModelXMLExporter;
import org.sonar.server.debt.DebtRulesXMLImporter;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.internal.SimpleGetRequest;
+import org.sonar.api.impl.ws.SimpleGetRequest;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.config.Encryption;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.config.Encryption;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.config.Encryption;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
-import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.Settings.GenerateSecretKeyWsResponse;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.PropertyFieldDefinition;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import okio.Buffer;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.mockito.internal.matchers.Any;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.core.platform.EditionProvider;
import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.resources.ResourceType;
import org.sonar.api.resources.ResourceTypeTree;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.web.page.Page;
import org.sonar.api.web.page.PageDefinition;
import org.sonar.core.platform.PluginInfo;
import org.junit.Test;
import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.security.LoginPasswordAuthenticator;
import org.sonar.api.security.SecurityRealm;
import org.sonar.api.utils.SonarException;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.server.ws.TestRequest;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.platform.NewUserHandler;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.server.authentication.CredentialsLocalAuthentication;
import org.sonar.server.es.EsTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.core.config.CorePropertyDefinitions;
import org.sonar.db.DbTester;
import org.sonar.db.user.GroupDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceType;
import org.sonar.api.resources.ResourceTypeTree;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceType;
import org.sonar.api.resources.ResourceTypeTree;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.utils.System2;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.db.DbTester;
import org.sonar.server.organization.TestOrganizationFlags;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.System2;
package org.sonar.server.user.ws;
import org.junit.Test;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.process.ProcessProperties;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.GroupDto;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDbTester;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
+import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
-import org.sonar.api.server.ws.internal.PartImpl;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.PartImpl;
+import org.sonar.api.impl.ws.ValidatingRequest;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import org.junit.rules.ExpectedException;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.apache.commons.io.IOUtils;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.internal.PartImpl;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.PartImpl;
+import org.sonar.api.impl.ws.ValidatingRequest;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.utils.text.XmlWriter;
import org.sonar.server.ws.WsTester.TestResponse.TestStream;
include 'sonar-duplications'
include 'sonar-markdown'
include 'sonar-plugin-api'
+include 'sonar-plugin-api-impl'
include 'sonar-scanner-engine'
include 'sonar-scanner-engine-shaded'
include 'sonar-scanner-protocol'
}
// Check the size of the archive
zip.doLast {
- def minLength = 185000000
- def maxLength = 199000000
+ def minLength = 198000000
+ def maxLength = 206000000
def length = archiveFile.get().asFile.length()
if (length < minLength)
throw new GradleException("$archiveName size ($length) too small. Min is $minLength")
import java.io.IOException;
import org.sonar.api.SonarEdition;
-import org.sonar.api.internal.MetadataLoader;
+import org.sonar.api.impl.context.MetadataLoader;
import org.sonar.application.command.CommandFactory;
import org.sonar.application.command.CommandFactoryImpl;
import org.sonar.application.command.JavaVersion;
compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.update-center:sonar-update-center-common'
compile project(path: ':sonar-plugin-api', configuration: 'shadow')
+ compile project(':sonar-plugin-api-impl')
compileOnly 'com.google.code.findbugs:jsr305'
import org.sonar.api.ExtensionProvider;
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
}
/**
- * @param container the container into which extensions will be installed
- * @param extensionFilter filters extensions added to {@link CoreExtension.Context}. When it returns false, the
- * extension is ignored as if it had never been added to the context.
+ * @param container the container into which extensions will be installed
+ * @param extensionFilter filters extensions added to {@link CoreExtension.Context}. When it returns false, the
+ * extension is ignored as if it had never been added to the context.
* @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether
* extension should be added to container as an object or only as a PropertyDefinition.
*/
import org.sonar.api.config.Configuration;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import static org.assertj.core.api.Assertions.assertThat;
@Test
@UseDataProvider("allMethodsToAddExtension")
- public void install_adds_providers_to_container_and_install_extensions_they_provide_when_annotated_with_expected_annotation(BiConsumer<CoreExtension.Context, Collection<Object>> extensionAdder) {
+ public void install_adds_providers_to_container_and_install_extensions_they_provide_when_annotated_with_expected_annotation(
+ BiConsumer<CoreExtension.Context, Collection<Object>> extensionAdder) {
List<Object> extensions = ImmutableList.of(WestSideProvider.class, PartiallyWestSideProvider.class, EastSideProvider.class);
CoreExtension coreExtension = newCoreExtension(context -> extensionAdder.accept(context, extensions));
when(coreExtensionRepository.loadedCoreExtensions()).thenReturn(Stream.of(coreExtension));
import java.util.TimeZone;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
import org.simpleframework.http.core.Container;
import org.simpleframework.transport.connect.SocketConnection;
import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.SonarException;
@Override
public boolean matches(Object ex) {
return
- // Java 8
- ex instanceof NoRouteToHostException || ex instanceof SocketException
- // Java 7 or before
- || ex instanceof SocketTimeoutException;
+ // Java 8
+ ex instanceof NoRouteToHostException || ex instanceof SocketException
+ // Java 7 or before
+ || ex instanceof SocketTimeoutException;
}
@Override
--- /dev/null
+sonarqube {
+ properties {
+ property 'sonar.projectName', "${projectTitle} :: Plugin API Implementation"
+ }
+}
+
+apply plugin: 'com.github.johnrengelman.shadow'
+
+dependencies {
+ // please keep the list grouped by configuration and ordered by name
+
+ compile 'commons-codec:commons-codec'
+ compile 'commons-io:commons-io'
+ compile 'commons-lang:commons-lang'
+ compile 'com.google.code.gson:gson'
+ compile 'org.apache.commons:commons-csv'
+
+ // shaded, but not relocated
+ compile project(':sonar-check-api')
+ compile project(':sonar-plugin-api')
+ compile project(':sonar-ws')
+
+
+ shadow 'org.codehaus.staxmate:staxmate'
+ shadow 'org.codehaus.woodstox:stax2-api'
+ shadow 'org.codehaus.woodstox:woodstox-core-lgpl'
+
+ compileOnly 'ch.qos.logback:logback-classic'
+ compileOnly 'ch.qos.logback:logback-core'
+ compileOnly 'com.google.code.findbugs:jsr305'
+ compileOnly 'javax.servlet:javax.servlet-api'
+ compileOnly 'junit:junit'
+ compileOnly 'org.slf4j:slf4j-api'
+
+ testCompile 'com.google.guava:guava'
+ testCompile 'com.tngtech.java:junit-dataprovider'
+ testCompile 'org.assertj:assertj-core'
+ testCompile 'org.mockito:mockito-core'
+ testCompile project(':sonar-scanner-engine')
+ testCompile project(':server:sonar-server')
+
+}
+
+sourceSets {
+ // Make the compileOnly dependencies available when compiling/running tests
+ test.compileClasspath += configurations.compileOnly + configurations.shadow
+ test.runtimeClasspath += configurations.compileOnly + configurations.shadow
+}
+
+def on3Digits(version) {
+ def projectversion3digits = version - ~/-\w+/
+ projectversion3digits = projectversion3digits.tokenize('.').plus(0).take(3).join('.')
+}
+
+import org.apache.tools.ant.filters.ReplaceTokens
+processResources {
+ filter ReplaceTokens, tokens: [
+ // The build version is composed of 4 fields, including the semantic version and the build number provided by Travis.
+ 'project.buildVersion': project.version.endsWith('SNAPSHOT') ? project.version : on3Digits(project.version) + '.' + System.getProperty("buildNumber"),
+ 'project.version.3digits': project.version.endsWith('SNAPSHOT') ? project.version : on3Digits(project.version)
+ ]
+}
+
+shadowJar {
+ configurations = [project.configurations.default]
+ relocate('com.google', 'org.sonar.api.internal.google')
+ relocate('org.apache.commons', 'org.sonar.api.internal.apachecommons')
+ dependencies {
+ exclude(dependency('org.codehaus.woodstox:woodstox-core-lgpl'))
+ exclude(dependency('org.codehaus.woodstox:stax2-api'))
+ exclude(dependency('org.codehaus.staxmate:staxmate'))
+ }
+}
+
+artifactoryPublish.skip = false
+
+publishing {
+ publications {
+ mavenJava(MavenPublication) {
+ artifact source: shadowJar, classifier: null
+ if (release) {
+ artifact sourcesJar
+ artifact javadocJar
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.rule.RuleKey;
+
+@Immutable
+public class DefaultActiveRule implements ActiveRule {
+ private final RuleKey ruleKey;
+ private final String severity;
+ private final String internalKey;
+ private final String language;
+ private final String templateRuleKey;
+ private final Map<String, String> params;
+ private final long createdAt;
+ private final long updatedAt;
+ private final String qProfileKey;
+
+ public DefaultActiveRule(NewActiveRule newActiveRule) {
+ this.severity = newActiveRule.severity;
+ this.internalKey = newActiveRule.internalKey;
+ this.templateRuleKey = newActiveRule.templateRuleKey;
+ this.ruleKey = newActiveRule.ruleKey;
+ this.params = Collections.unmodifiableMap(new HashMap<>(newActiveRule.params));
+ this.language = newActiveRule.language;
+ this.createdAt = newActiveRule.createdAt;
+ this.updatedAt = newActiveRule.updatedAt;
+ this.qProfileKey = newActiveRule.qProfileKey;
+ }
+
+ @Override
+ public RuleKey ruleKey() {
+ return ruleKey;
+ }
+
+ @Override
+ public String severity() {
+ return severity;
+ }
+
+ @Override
+ public String language() {
+ return language;
+ }
+
+ @Override
+ public String param(String key) {
+ return params.get(key);
+ }
+
+ @Override
+ public Map<String, String> params() {
+ // already immutable
+ return params;
+ }
+
+ @Override
+ public String internalKey() {
+ return internalKey;
+ }
+
+ @Override
+ public String templateRuleKey() {
+ return templateRuleKey;
+ }
+
+ public long createdAt() {
+ return createdAt;
+ }
+
+ public long updatedAt() {
+ return updatedAt;
+ }
+
+ @Override
+ public String qpKey() {
+ return qProfileKey;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+
+@Immutable
+public class DefaultRule implements Rule {
+
+ private final RuleKey key;
+ private final Integer id;
+ private final String name;
+ private final String severity;
+ private final String type;
+ private final String description;
+ private final String internalKey;
+ private final RuleStatus status;
+ private final Map<String, RuleParam> params;
+
+ public DefaultRule(NewRule newRule) {
+ this.key = newRule.key;
+ this.id = newRule.id;
+ this.name = newRule.name;
+ this.severity = newRule.severity;
+ this.type = newRule.type;
+ this.description = newRule.description;
+ this.internalKey = newRule.internalKey;
+ this.status = newRule.status;
+
+ Map<String, RuleParam> builder = new HashMap<>();
+ for (NewRuleParam newRuleParam : newRule.params.values()) {
+ builder.put(newRuleParam.key, new DefaultRuleParam(newRuleParam));
+ }
+ params = Collections.unmodifiableMap(builder);
+ }
+
+ @Override
+ public RuleKey key() {
+ return key;
+ }
+
+ @CheckForNull
+ public Integer id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public String severity() {
+ return severity;
+ }
+
+ @CheckForNull
+ public String type() {
+ return type;
+ }
+
+ @Override
+ public String description() {
+ return description;
+ }
+
+ @Override
+ public String internalKey() {
+ return internalKey;
+ }
+
+ @Override
+ public RuleStatus status() {
+ return status;
+ }
+
+ @Override
+ public RuleParam param(String paramKey) {
+ return params.get(paramKey);
+ }
+
+ @Override
+ public Collection<RuleParam> params() {
+ return params.values();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+class DefaultRuleParam implements RuleParam {
+
+ private final String key;
+ private final String description;
+
+ DefaultRuleParam(NewRuleParam p) {
+ this.key = p.key;
+ this.description = p.description;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ @Nullable
+ public String description() {
+ return description;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.config;
+
+import java.util.Optional;
+import org.sonar.api.config.Settings;
+import org.sonar.api.config.Configuration;
+
+/**
+ * Used to help migration from {@link Settings} to {@link Configuration}
+ */
+public class ConfigurationBridge implements Configuration {
+
+ private final Settings settings;
+
+ public ConfigurationBridge(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public Optional<String> get(String key) {
+ return Optional.ofNullable(settings.getString(key));
+ }
+
+ @Override
+ public boolean hasKey(String key) {
+ return settings.hasKey(key);
+ }
+
+ @Override
+ public String[] getStringArray(String key) {
+ return settings.getStringArray(key);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.config.Encryption;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+
+import static java.util.Collections.unmodifiableMap;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * In-memory map-based implementation of {@link Settings}. It must be used
+ * <b>only for unit tests</b>. This is not the implementation
+ * deployed at runtime, so non-test code must never cast
+ * {@link Settings} to {@link MapSettings}.
+ *
+ * @since 6.1
+ */
+public class MapSettings extends Settings {
+
+ private final Map<String, String> props = new HashMap<>();
+ private final ConfigurationBridge configurationBridge;
+
+ public MapSettings() {
+ this(new PropertyDefinitions());
+ }
+
+ public MapSettings(PropertyDefinitions definitions) {
+ super(definitions, new Encryption(null));
+ configurationBridge = new ConfigurationBridge(this);
+ }
+
+ @Override
+ protected Optional<String> get(String key) {
+ return Optional.ofNullable(props.get(key));
+ }
+
+ @Override
+ protected void set(String key, String value) {
+ props.put(
+ requireNonNull(key, "key can't be null"),
+ requireNonNull(value, "value can't be null").trim());
+ }
+
+ @Override
+ protected void remove(String key) {
+ props.remove(key);
+ }
+
+ @Override
+ public Map<String, String> getProperties() {
+ return unmodifiableMap(props);
+ }
+
+ /**
+ * Delete all properties
+ */
+ public MapSettings clear() {
+ props.clear();
+ return this;
+ }
+
+ @Override
+ public MapSettings setProperty(String key, String value) {
+ return (MapSettings) super.setProperty(key, value);
+ }
+
+ @Override
+ public MapSettings setProperty(String key, Integer value) {
+ return (MapSettings) super.setProperty(key, value);
+ }
+
+ @Override
+ public MapSettings setProperty(String key, Boolean value) {
+ return (MapSettings) super.setProperty(key, value);
+ }
+
+ @Override
+ public MapSettings setProperty(String key, Long value) {
+ return (MapSettings) super.setProperty(key, value);
+ }
+
+ /**
+ * @return a {@link Configuration} proxy on top of this existing {@link Settings} implementation. Changes are reflected in the {@link Configuration} object.
+ * @since 6.5
+ */
+ public Configuration asConfig() {
+ return configurationBridge;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.config;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+import org.apache.commons.lang.ArrayUtils;
+
+public class MultivalueProperty {
+ private MultivalueProperty() {
+ // prevents instantiation
+ }
+
+ public static String[] parseAsCsv(String key, String value) {
+ return parseAsCsv(key, value, Function.identity());
+ }
+
+ public static String[] parseAsCsv(String key, String value, Function<String, String> valueProcessor) {
+ String cleanValue = MultivalueProperty.trimFieldsAndRemoveEmptyFields(value);
+ List<String> result = new ArrayList<>();
+ try (CSVParser csvParser = CSVFormat.RFC4180
+ .withHeader((String) null)
+ .withIgnoreEmptyLines()
+ .withIgnoreSurroundingSpaces()
+ .parse(new StringReader(cleanValue))) {
+ List<CSVRecord> records = csvParser.getRecords();
+ if (records.isEmpty()) {
+ return ArrayUtils.EMPTY_STRING_ARRAY;
+ }
+ processRecords(result, records, valueProcessor);
+ return result.toArray(new String[result.size()]);
+ } catch (IOException e) {
+ throw new IllegalStateException("Property: '" + key + "' doesn't contain a valid CSV value: '" + value + "'", e);
+ }
+ }
+
+ /**
+ * In most cases we expect a single record. <br>Having multiple records means the input value was splitted over multiple lines (this is common in Maven).
+ * For example:
+ * <pre>
+ * <sonar.exclusions>
+ * src/foo,
+ * src/bar,
+ * src/biz
+ * <sonar.exclusions>
+ * </pre>
+ * In this case records will be merged to form a single list of items. Last item of a record is appended to first item of next record.
+ * <p>
+ * This is a very curious case, but we try to preserve line break in the middle of an item:
+ * <pre>
+ * <sonar.exclusions>
+ * a
+ * b,
+ * c
+ * <sonar.exclusions>
+ * </pre>
+ * will produce ['a\nb', 'c']
+ */
+ private static void processRecords(List<String> result, List<CSVRecord> records, Function<String, String> valueProcessor) {
+ for (CSVRecord csvRecord : records) {
+ Iterator<String> it = csvRecord.iterator();
+ if (!result.isEmpty()) {
+ String next = it.next();
+ if (!next.isEmpty()) {
+ int lastItemIdx = result.size() - 1;
+ String previous = result.get(lastItemIdx);
+ if (previous.isEmpty()) {
+ result.set(lastItemIdx, valueProcessor.apply(next));
+ } else {
+ result.set(lastItemIdx, valueProcessor.apply(previous + "\n" + next));
+ }
+ }
+ }
+ it.forEachRemaining(s -> {
+ String apply = valueProcessor.apply(s);
+ result.add(apply);
+ });
+ }
+ }
+
+ /**
+ * Removes the empty fields from the value of a multi-value property from empty fields, including trimming each field.
+ * <p>
+ * Quotes can be used to prevent an empty field to be removed (as it is used to preserve empty spaces).
+ * <ul>
+ * <li>{@code "" => ""}</li>
+ * <li>{@code " " => ""}</li>
+ * <li>{@code "," => ""}</li>
+ * <li>{@code ",," => ""}</li>
+ * <li>{@code ",,," => ""}</li>
+ * <li>{@code ",a" => "a"}</li>
+ * <li>{@code "a," => "a"}</li>
+ * <li>{@code ",a," => "a"}</li>
+ * <li>{@code "a,,b" => "a,b"}</li>
+ * <li>{@code "a, ,b" => "a,b"}</li>
+ * <li>{@code "a,\"\",b" => "a,b"}</li>
+ * <li>{@code "\"a\",\"b\"" => "\"a\",\"b\""}</li>
+ * <li>{@code "\" a \",\"b \"" => "\" a \",\"b \""}</li>
+ * <li>{@code "\"a\",\"\",\"b\"" => "\"a\",\"\",\"b\""}</li>
+ * <li>{@code "\"a\",\" \",\"b\"" => "\"a\",\" \",\"b\""}</li>
+ * <li>{@code "\" a,,b,c \",\"d \"" => "\" a,,b,c \",\"d \""}</li>
+ * <li>{@code "a,\" \",b" => "ab"]}</li>
+ * </ul>
+ */
+ static String trimFieldsAndRemoveEmptyFields(String str) {
+ char[] chars = str.toCharArray();
+ char[] res = new char[chars.length];
+ /*
+ * set when reading the first non trimmable char after a separator char (or the beginning of the string)
+ * unset when reading a separator
+ */
+ boolean inField = false;
+ boolean inQuotes = false;
+ int i = 0;
+ int resI = 0;
+ for (; i < chars.length; i++) {
+ boolean isSeparator = chars[i] == ',';
+ if (!inQuotes && isSeparator) {
+ // exiting field (may already be unset)
+ inField = false;
+ if (resI > 0) {
+ resI = retroTrim(res, resI);
+ }
+ } else {
+ boolean isTrimmed = !inQuotes && istrimmable(chars[i]);
+ if (isTrimmed && !inField) {
+ // we haven't meet any non trimmable char since the last separator yet
+ continue;
+ }
+
+ boolean isEscape = isEscapeChar(chars[i]);
+ if (isEscape) {
+ inQuotes = !inQuotes;
+ }
+
+ // add separator as we already had one field
+ if (!inField && resI > 0) {
+ res[resI] = ',';
+ resI++;
+ }
+
+ // register in field (may already be set)
+ inField = true;
+ // copy current char
+ res[resI] = chars[i];
+ resI++;
+ }
+ }
+ // inQuotes can only be true at this point if quotes are unbalanced
+ if (!inQuotes) {
+ // trim end of str
+ resI = retroTrim(res, resI);
+ }
+ return new String(res, 0, resI);
+ }
+
+ private static boolean isEscapeChar(char aChar) {
+ return aChar == '"';
+ }
+
+ private static boolean istrimmable(char aChar) {
+ return aChar <= ' ';
+ }
+
+ /**
+ * Reads from index {@code resI} to the beginning into {@code res} looking up the location of the trimmable char with
+ * the lowest index before encountering a non-trimmable char.
+ * <p>
+ * This basically trims {@code res} from any trimmable char at its end.
+ *
+ * @return index of next location to put new char in res
+ */
+ private static int retroTrim(char[] res, int resI) {
+ int i = resI;
+ while (i >= 1) {
+ if (!istrimmable(res[i - 1])) {
+ return i;
+ }
+ i--;
+ }
+ return i;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.config;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.context;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Scanner;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.Version;
+
+import static org.apache.commons.lang.StringUtils.trimToEmpty;
+
+/**
+ * For internal use
+ *
+ * @since 7.8
+ */
+public class MetadataLoader {
+
+ private static final String VERSION_FILE_PATH = "/sonar-api-version.txt";
+ private static final String EDITION_FILE_PATH = "/sonar-edition.txt";
+
+ private MetadataLoader() {
+ // only static methods
+ }
+
+ public static Version loadVersion(System2 system) {
+ URL url = system.getResource(VERSION_FILE_PATH);
+
+ try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name())) {
+ String versionInFile = scanner.nextLine();
+ return Version.parse(versionInFile);
+ } catch (IOException e) {
+ throw new IllegalStateException("Can not load " + VERSION_FILE_PATH + " from classpath ", e);
+ }
+ }
+
+ public static SonarEdition loadEdition(System2 system) {
+ URL url = system.getResource(EDITION_FILE_PATH);
+ if (url == null) {
+ return SonarEdition.COMMUNITY;
+ }
+ try (Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name())) {
+ String editionInFile = scanner.nextLine();
+ return parseEdition(editionInFile);
+ } catch (IOException e) {
+ throw new IllegalStateException("Can not load " + EDITION_FILE_PATH + " from classpath", e);
+ }
+ }
+
+ static SonarEdition parseEdition(String edition) {
+ String str = trimToEmpty(edition.toUpperCase());
+ try {
+ return SonarEdition.valueOf(str);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(String.format("Invalid edition found in '%s': '%s'", EDITION_FILE_PATH, str));
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.context;
+
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.impl.config.MapSettings;
+
+/**
+ * Implementation of {@link Plugin.Context} that plugins could use in their unit tests.
+ *
+ * Example:
+ *
+ * <pre>
+ * import org.sonar.api.internal.SonarRuntimeImpl;
+ * import org.sonar.api.config.internal.MapSettings;
+ *
+ * ...
+ *
+ * SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 1), SonarQubeSide.SCANNER);
+ * MapSettings settings = new MapSettings().setProperty("foo", "bar");
+ * Plugin.Context context = new PluginContextImpl.Builder()
+ * .setSonarRuntime(runtime)
+ * .setBootConfiguration(settings.asConfig());
+ * .build();
+ * </pre>
+ *
+ * @since 7.1
+ */
+public class PluginContextImpl extends Plugin.Context {
+
+ private final Configuration bootConfiguration;
+
+ private PluginContextImpl(Builder builder) {
+ super(builder.sonarRuntime);
+ this.bootConfiguration = builder.bootConfiguration != null ? builder.bootConfiguration : new MapSettings().asConfig();
+ }
+
+ @Override
+ public Configuration getBootConfiguration() {
+ return bootConfiguration;
+ }
+
+ public static class Builder {
+ private SonarRuntime sonarRuntime;
+ private Configuration bootConfiguration;
+
+ /**
+ * Required.
+ * @see SonarRuntimeImpl
+ * @return this
+ */
+ public Builder setSonarRuntime(SonarRuntime r) {
+ this.sonarRuntime = r;
+ return this;
+ }
+
+ /**
+ * If not set, then an empty configuration is used.
+ * @return this
+ */
+ public Builder setBootConfiguration(Configuration c) {
+ this.bootConfiguration = c;
+ return this;
+ }
+
+ public Plugin.Context build() {
+ return new PluginContextImpl(this);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.context;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarProduct;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.utils.Version;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+/**
+ * @since 6.0
+ */
+@Immutable
+public class SonarRuntimeImpl implements SonarRuntime {
+
+ private final Version version;
+ private final SonarProduct product;
+ private final SonarQubeSide sonarQubeSide;
+ private final SonarEdition edition;
+
+ private SonarRuntimeImpl(Version version, SonarProduct product, @Nullable SonarQubeSide sonarQubeSide, @Nullable SonarEdition edition) {
+ this.edition = edition;
+ requireNonNull(product);
+ checkArgument((product == SonarProduct.SONARQUBE) == (sonarQubeSide != null), "sonarQubeSide should be provided only for SonarQube product");
+ checkArgument((product == SonarProduct.SONARQUBE) == (edition != null), "edition should be provided only for SonarQube product");
+ this.version = requireNonNull(version);
+ this.product = product;
+ this.sonarQubeSide = sonarQubeSide;
+ }
+
+ @Override
+ public Version getApiVersion() {
+ return version;
+ }
+
+ @Override
+ public SonarProduct getProduct() {
+ return product;
+ }
+
+ @Override
+ public SonarQubeSide getSonarQubeSide() {
+ if (sonarQubeSide == null) {
+ throw new UnsupportedOperationException("Can only be called in SonarQube");
+ }
+ return sonarQubeSide;
+ }
+
+ @Override
+ public SonarEdition getEdition() {
+ if (sonarQubeSide == null) {
+ throw new UnsupportedOperationException("Can only be called in SonarQube");
+ }
+ return edition;
+ }
+
+ /**
+ * Create an instance for SonarQube runtime environment.
+ */
+ public static SonarRuntime forSonarQube(Version version, SonarQubeSide side, SonarEdition edition) {
+ return new SonarRuntimeImpl(version, SonarProduct.SONARQUBE, side, edition);
+ }
+
+ /**
+ * Create an instance for SonarLint runtime environment.
+ */
+ public static SonarRuntime forSonarLint(Version version) {
+ return new SonarRuntimeImpl(version, SonarProduct.SONARLINT, null, null);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.context;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.SystemUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+@Immutable
+public abstract class AbstractProjectOrModule extends DefaultInputComponent {
+ private static final Logger LOGGER = Loggers.get(AbstractProjectOrModule.class);
+ private final Path baseDir;
+ private final Path workDir;
+ private final String name;
+ private final String originalName;
+ private final String description;
+ private final String keyWithBranch;
+ private final String branch;
+ private final Map<String, String> properties;
+
+ private final String key;
+ private final ProjectDefinition definition;
+ private final Charset encoding;
+
+ public AbstractProjectOrModule(ProjectDefinition definition, int scannerComponentId) {
+ super(scannerComponentId);
+ this.baseDir = initBaseDir(definition);
+ this.workDir = initWorkingDir(definition);
+ this.name = definition.getName();
+ this.originalName = definition.getOriginalName();
+ this.description = definition.getDescription();
+ this.keyWithBranch = definition.getKeyWithBranch();
+ this.branch = definition.getBranch();
+ this.properties = Collections.unmodifiableMap(new HashMap<>(definition.properties()));
+
+ this.definition = definition;
+ this.key = definition.getKey();
+ this.encoding = initEncoding(definition);
+ }
+
+ private static Charset initEncoding(ProjectDefinition module) {
+ String encodingStr = module.properties().get(CoreProperties.ENCODING_PROPERTY);
+ Charset result;
+ if (StringUtils.isNotEmpty(encodingStr)) {
+ result = Charset.forName(StringUtils.trim(encodingStr));
+ } else {
+ result = Charset.defaultCharset();
+ }
+ return result;
+ }
+
+ private static Path initBaseDir(ProjectDefinition module) {
+ Path result;
+ try {
+ result = module.getBaseDir().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to resolve module baseDir", e);
+ }
+ return result;
+ }
+
+ private static Path initWorkingDir(ProjectDefinition module) {
+ File workingDirAsFile = module.getWorkDir();
+ Path workingDir = workingDirAsFile.getAbsoluteFile().toPath().normalize();
+ if (SystemUtils.IS_OS_WINDOWS) {
+ try {
+ Files.createDirectories(workingDir);
+ Files.setAttribute(workingDir, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS);
+ } catch (IOException e) {
+ LOGGER.warn("Failed to set working directory hidden: {}", e.getMessage());
+ }
+ }
+ return workingDir;
+ }
+
+ /**
+ * Module key without branch
+ */
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public boolean isFile() {
+ return false;
+ }
+
+ public ProjectDefinition definition() {
+ return definition;
+ }
+
+ public Path getBaseDir() {
+ return baseDir;
+ }
+
+ public Path getWorkDir() {
+ return workDir;
+ }
+
+ public String getKeyWithBranch() {
+ return keyWithBranch;
+ }
+
+ @CheckForNull
+ public String getBranch() {
+ return branch;
+ }
+
+ public Map<String, String> properties() {
+ return properties;
+ }
+
+ @CheckForNull
+ public String getOriginalName() {
+ return originalName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Charset getEncoding() {
+ return encoding;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.StreamSupport;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FilePredicates;
+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.impl.fs.predicates.DefaultFilePredicates;
+import org.sonar.api.impl.fs.predicates.FileExtensionPredicate;
+import org.sonar.api.impl.fs.predicates.OptimizedFilePredicateAdapter;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * @since 4.2
+ */
+public class DefaultFileSystem implements FileSystem {
+
+ private final Cache cache;
+ private final FilePredicates predicates;
+ private final Path baseDir;
+ private Path workDir;
+ private Charset encoding;
+
+ /**
+ * Only for testing
+ */
+ public DefaultFileSystem(Path baseDir) {
+ this(baseDir, new MapCache(), new DefaultFilePredicates(baseDir));
+ }
+
+ /**
+ * Only for testing
+ */
+ public DefaultFileSystem(File baseDir) {
+ this(baseDir.toPath(), new MapCache(), new DefaultFilePredicates(baseDir.toPath()));
+ }
+
+ protected DefaultFileSystem(Path baseDir, Cache cache, FilePredicates filePredicates) {
+ this.baseDir = baseDir;
+ this.cache = cache;
+ this.predicates = filePredicates;
+ }
+
+ public Path baseDirPath() {
+ return baseDir;
+ }
+
+ @Override
+ public File baseDir() {
+ return baseDir.toFile();
+ }
+
+ public DefaultFileSystem setEncoding(Charset e) {
+ this.encoding = e;
+ return this;
+ }
+
+ @Override
+ public Charset encoding() {
+ return encoding;
+ }
+
+ public DefaultFileSystem setWorkDir(Path d) {
+ this.workDir = d;
+ return this;
+ }
+
+ @Override
+ public File workDir() {
+ return workDir.toFile();
+ }
+
+ @Override
+ public InputFile inputFile(FilePredicate predicate) {
+ Iterable<InputFile> files = inputFiles(predicate);
+ Iterator<InputFile> iterator = files.iterator();
+ if (!iterator.hasNext()) {
+ return null;
+ }
+ InputFile first = iterator.next();
+ if (!iterator.hasNext()) {
+ return first;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("expected one element but was: <" + first);
+ for (int i = 0; i < 4 && iterator.hasNext(); i++) {
+ sb.append(", " + iterator.next());
+ }
+ if (iterator.hasNext()) {
+ sb.append(", ...");
+ }
+ sb.append('>');
+
+ throw new IllegalArgumentException(sb.toString());
+
+ }
+
+ public Iterable<InputFile> inputFiles() {
+ return inputFiles(predicates.all());
+ }
+
+ @Override
+ public Iterable<InputFile> inputFiles(FilePredicate predicate) {
+ return OptimizedFilePredicateAdapter.create(predicate).get(cache);
+ }
+
+ @Override
+ public boolean hasFiles(FilePredicate predicate) {
+ return inputFiles(predicate).iterator().hasNext();
+ }
+
+ @Override
+ public Iterable<File> files(FilePredicate predicate) {
+ return () -> StreamSupport.stream(inputFiles(predicate).spliterator(), false)
+ .map(InputFile::file)
+ .iterator();
+ }
+
+ @Override
+ public InputDir inputDir(File dir) {
+ String relativePath = PathUtils.sanitize(new PathResolver().relativePath(baseDir.toFile(), dir));
+ if (relativePath == null) {
+ return null;
+ }
+ // Issues on InputDir are moved to the project, so we just return a fake InputDir for backward compatibility
+ return new DefaultInputDir("unused", relativePath).setModuleBaseDir(baseDir);
+ }
+
+ public DefaultFileSystem add(InputFile inputFile) {
+ cache.add(inputFile);
+ return this;
+ }
+
+ @Override
+ public SortedSet<String> languages() {
+ return cache.languages();
+ }
+
+ @Override
+ public FilePredicates predicates() {
+ return predicates;
+ }
+
+ public abstract static class Cache implements Index {
+
+ protected abstract void doAdd(InputFile inputFile);
+
+ final void add(InputFile inputFile) {
+ doAdd(inputFile);
+ }
+
+ protected abstract SortedSet<String> languages();
+ }
+
+ /**
+ * Used only for testing
+ */
+ private static class MapCache extends Cache {
+ private final Map<String, InputFile> fileMap = new HashMap<>();
+ private final Map<String, Set<InputFile>> filesByNameCache = new HashMap<>();
+ private final Map<String, Set<InputFile>> filesByExtensionCache = new HashMap<>();
+ private SortedSet<String> languages = new TreeSet<>();
+
+ @Override
+ public Iterable<InputFile> inputFiles() {
+ return new ArrayList<>(fileMap.values());
+ }
+
+ @Override
+ public InputFile inputFile(String relativePath) {
+ return fileMap.get(relativePath);
+ }
+
+ @Override
+ public Iterable<InputFile> getFilesByName(String filename) {
+ return filesByNameCache.get(filename);
+ }
+
+ @Override
+ public Iterable<InputFile> getFilesByExtension(String extension) {
+ return filesByExtensionCache.get(extension);
+ }
+
+ @Override
+ protected void doAdd(InputFile inputFile) {
+ if (inputFile.language() != null) {
+ languages.add(inputFile.language());
+ }
+ fileMap.put(inputFile.relativePath(), inputFile);
+ filesByNameCache.computeIfAbsent(inputFile.filename(), x -> new HashSet<>()).add(inputFile);
+ filesByExtensionCache.computeIfAbsent(FileExtensionPredicate.getExtension(inputFile), x -> new HashSet<>()).add(inputFile);
+ }
+
+ @Override
+ protected SortedSet<String> languages() {
+ return languages;
+ }
+ }
+
+ @Override
+ public File resolvePath(String path) {
+ File file = new File(path);
+ if (!file.isAbsolute()) {
+ try {
+ file = new File(baseDir(), path).getCanonicalFile();
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Unable to resolve path '" + path + "'", e);
+ }
+ }
+ return file;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.fs.IndexedFile;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * @since 6.3
+ */
+@Immutable
+public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile {
+ private static AtomicInteger intGenerator = new AtomicInteger(0);
+
+ private final String projectRelativePath;
+ private final String moduleRelativePath;
+ private final String projectKey;
+ private final String language;
+ private final Type type;
+ private final Path absolutePath;
+ private final SensorStrategy sensorStrategy;
+
+ /**
+ * Testing purposes only!
+ */
+ public DefaultIndexedFile(String projectKey, Path baseDir, String relativePath, @Nullable String language) {
+ this(baseDir.resolve(relativePath), projectKey, relativePath, relativePath, Type.MAIN, language, intGenerator.getAndIncrement(),
+ new SensorStrategy());
+ }
+
+ public DefaultIndexedFile(Path absolutePath, String projectKey, String projectRelativePath, String moduleRelativePath, Type type, @Nullable String language, int batchId,
+ SensorStrategy sensorStrategy) {
+ super(batchId);
+ this.projectKey = projectKey;
+ this.projectRelativePath = PathUtils.sanitize(projectRelativePath);
+ this.moduleRelativePath = PathUtils.sanitize(moduleRelativePath);
+ this.type = type;
+ this.language = language;
+ this.sensorStrategy = sensorStrategy;
+ this.absolutePath = absolutePath;
+ }
+
+ @Override
+ public String relativePath() {
+ return sensorStrategy.isGlobal() ? projectRelativePath : moduleRelativePath;
+ }
+
+ public String getModuleRelativePath() {
+ return moduleRelativePath;
+ }
+
+ public String getProjectRelativePath() {
+ return projectRelativePath;
+ }
+
+ @Override
+ public String absolutePath() {
+ return PathUtils.sanitize(path().toString());
+ }
+
+ @Override
+ public File file() {
+ return path().toFile();
+ }
+
+ @Override
+ public Path path() {
+ return absolutePath;
+ }
+
+ @Override
+ public InputStream inputStream() throws IOException {
+ return Files.newInputStream(path());
+ }
+
+ @CheckForNull
+ @Override
+ public String language() {
+ return language;
+ }
+
+ @Override
+ public Type type() {
+ return type;
+ }
+
+ /**
+ * Component key (without branch).
+ */
+ @Override
+ public String key() {
+ return new StringBuilder().append(projectKey).append(":").append(projectRelativePath).toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof DefaultIndexedFile)) {
+ return false;
+ }
+
+ DefaultIndexedFile that = (DefaultIndexedFile) o;
+ return projectRelativePath.equals(that.projectRelativePath);
+ }
+
+ @Override
+ public int hashCode() {
+ return projectRelativePath.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return projectRelativePath;
+ }
+
+ @Override
+ public boolean isFile() {
+ return true;
+ }
+
+ @Override
+ public String filename() {
+ return path().getFileName().toString();
+ }
+
+ @Override
+ public URI uri() {
+ return path().toUri();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.measure.Metric;
+
+/**
+ * @since 5.2
+ */
+public abstract class DefaultInputComponent implements InputComponent {
+ private int id;
+ private Set<String> storedMetricKeys = new HashSet<>();
+
+ public DefaultInputComponent(int scannerId) {
+ this.id = scannerId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || this.getClass() != o.getClass()) {
+ return false;
+ }
+
+ DefaultInputComponent that = (DefaultInputComponent) o;
+ return key().equals(that.key());
+ }
+
+ public int scannerId() {
+ return id;
+ }
+
+ @Override
+ public int hashCode() {
+ return key().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "[key=" + key() + "]";
+ }
+
+ public void setHasMeasureFor(Metric metric) {
+ storedMetricKeys.add(metric.key());
+ }
+
+ public boolean hasMeasureFor(Metric metric) {
+ return storedMetricKeys.contains(metric.key());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.batch.fs.InputDir;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * @since 4.5
+ */
+public class DefaultInputDir extends DefaultInputComponent implements InputDir {
+
+ private final String relativePath;
+ private final String moduleKey;
+ private Path moduleBaseDir;
+
+ public DefaultInputDir(String moduleKey, String relativePath) {
+ super(-1);
+ this.moduleKey = moduleKey;
+ this.relativePath = PathUtils.sanitize(relativePath);
+ }
+
+ @Override
+ public String relativePath() {
+ return relativePath;
+ }
+
+ @Override
+ public String absolutePath() {
+ return PathUtils.sanitize(path().toString());
+ }
+
+ @Override
+ public File file() {
+ return path().toFile();
+ }
+
+ @Override
+ public Path path() {
+ if (moduleBaseDir == null) {
+ throw new IllegalStateException("Can not return the java.nio.file.Path because module baseDir is not set (see method setModuleBaseDir(java.io.File))");
+ }
+ return moduleBaseDir.resolve(relativePath);
+ }
+
+ public String moduleKey() {
+ return moduleKey;
+ }
+
+ @Override
+ public String key() {
+ StringBuilder sb = new StringBuilder().append(moduleKey).append(":");
+ if (StringUtils.isEmpty(relativePath)) {
+ sb.append("/");
+ } else {
+ sb.append(relativePath);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * For testing purpose. Will be automatically set when dir is added to {@link DefaultFileSystem}
+ */
+ public DefaultInputDir setModuleBaseDir(Path moduleBaseDir) {
+ this.moduleBaseDir = moduleBaseDir.normalize();
+ return this;
+ }
+
+ @Override
+ public boolean isFile() {
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || this.getClass() != o.getClass()) {
+ return false;
+ }
+
+ DefaultInputDir that = (DefaultInputDir) o;
+ return moduleKey.equals(that.moduleKey) && relativePath.equals(that.relativePath);
+ }
+
+ @Override
+ public int hashCode() {
+ return moduleKey.hashCode() + relativePath.hashCode() * 13;
+ }
+
+ @Override
+ public String toString() {
+ return "[moduleKey=" + moduleKey + ", relative=" + relativePath + ", basedir=" + moduleBaseDir + "]";
+ }
+
+ @Override
+ public URI uri() {
+ return path().toUri();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.io.ByteOrderMark;
+import org.apache.commons.io.input.BOMInputStream;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextPointer;
+import org.sonar.api.batch.fs.TextRange;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+/**
+ * @since 4.2
+ * To create {@link InputFile} in tests, use TestInputFileBuilder.
+ */
+public class DefaultInputFile extends DefaultInputComponent implements InputFile {
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ private final DefaultIndexedFile indexedFile;
+ private final String contents;
+ private final Consumer<DefaultInputFile> metadataGenerator;
+
+ private boolean published;
+ private boolean excludedForCoverage;
+ private boolean excludedForDuplication;
+ private boolean ignoreAllIssues;
+ // Lazy init to save memory
+ private BitSet noSonarLines;
+ private Status status;
+ private Charset charset;
+ private Metadata metadata;
+ private Collection<int[]> ignoreIssuesOnlineRanges;
+ private BitSet executableLines;
+
+ public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) {
+ this(indexedFile, metadataGenerator, null);
+ }
+
+ // For testing
+ public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator, @Nullable String contents) {
+ super(indexedFile.scannerId());
+ this.indexedFile = indexedFile;
+ this.metadataGenerator = metadataGenerator;
+ this.metadata = null;
+ this.published = false;
+ this.excludedForCoverage = false;
+ this.contents = contents;
+ }
+
+ public void checkMetadata() {
+ if (metadata == null) {
+ metadataGenerator.accept(this);
+ }
+ }
+
+ @Override
+ public InputStream inputStream() throws IOException {
+ return contents != null ? new ByteArrayInputStream(contents.getBytes(charset()))
+ : new BOMInputStream(Files.newInputStream(path()),
+ ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
+ }
+
+ @Override
+ public String contents() throws IOException {
+ if (contents != null) {
+ return contents;
+ } else {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ try (InputStream inputStream = inputStream()) {
+ byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+ }
+ return result.toString(charset().name());
+ }
+ }
+
+ public DefaultInputFile setPublished(boolean published) {
+ this.published = published;
+ return this;
+ }
+
+ public boolean isPublished() {
+ return published;
+ }
+
+ public DefaultInputFile setExcludedForCoverage(boolean excludedForCoverage) {
+ this.excludedForCoverage = excludedForCoverage;
+ return this;
+ }
+
+ public boolean isExcludedForCoverage() {
+ return excludedForCoverage;
+ }
+
+ public DefaultInputFile setExcludedForDuplication(boolean excludedForDuplication) {
+ this.excludedForDuplication = excludedForDuplication;
+ return this;
+ }
+
+ public boolean isExcludedForDuplication() {
+ return excludedForDuplication;
+ }
+
+ /**
+ * @deprecated since 6.6
+ */
+ @Deprecated
+ @Override
+ public String relativePath() {
+ return indexedFile.relativePath();
+ }
+
+ public String getModuleRelativePath() {
+ return indexedFile.getModuleRelativePath();
+ }
+
+ public String getProjectRelativePath() {
+ return indexedFile.getProjectRelativePath();
+ }
+
+ @Override
+ public String absolutePath() {
+ return indexedFile.absolutePath();
+ }
+
+ @Override
+ public File file() {
+ return indexedFile.file();
+ }
+
+ @Override
+ public Path path() {
+ return indexedFile.path();
+ }
+
+ @CheckForNull
+ @Override
+ public String language() {
+ return indexedFile.language();
+ }
+
+ @Override
+ public Type type() {
+ return indexedFile.type();
+ }
+
+ /**
+ * Component key (without branch).
+ */
+ @Override
+ public String key() {
+ return indexedFile.key();
+ }
+
+ @Override
+ public int hashCode() {
+ return indexedFile.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return indexedFile.toString();
+ }
+
+ /**
+ * {@link #setStatus(Status)}
+ */
+ @Override
+ public Status status() {
+ checkMetadata();
+ return status;
+ }
+
+ @Override
+ public int lines() {
+ checkMetadata();
+ return metadata.lines();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ checkMetadata();
+ return metadata.isEmpty();
+ }
+
+ @Override
+ public Charset charset() {
+ checkMetadata();
+ return charset;
+ }
+
+ public int lastValidOffset() {
+ checkMetadata();
+ return metadata.lastValidOffset();
+ }
+
+ /**
+ * Digest hash of the file.
+ */
+ public String hash() {
+ checkMetadata();
+ return metadata.hash();
+ }
+
+ public int nonBlankLines() {
+ checkMetadata();
+ return metadata.nonBlankLines();
+ }
+
+ public int[] originalLineStartOffsets() {
+ checkMetadata();
+ checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized.");
+ checkState(metadata.originalLineStartOffsets().length == metadata.lines(),
+ "InputFile is not properly initialized. 'originalLineStartOffsets' property length should be equal to 'lines'");
+ return metadata.originalLineStartOffsets();
+ }
+
+ public int[] originalLineEndOffsets() {
+ checkMetadata();
+ checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized.");
+ checkState(metadata.originalLineEndOffsets().length == metadata.lines(),
+ "InputFile is not properly initialized. 'originalLineEndOffsets' property length should be equal to 'lines'");
+ return metadata.originalLineEndOffsets();
+ }
+
+ @Override
+ public TextPointer newPointer(int line, int lineOffset) {
+ checkMetadata();
+ DefaultTextPointer textPointer = new DefaultTextPointer(line, lineOffset);
+ checkValid(textPointer, "pointer");
+ return textPointer;
+ }
+
+ @Override
+ public TextRange newRange(TextPointer start, TextPointer end) {
+ checkMetadata();
+ checkValid(start, "start pointer");
+ checkValid(end, "end pointer");
+ return newRangeValidPointers(start, end, false);
+ }
+
+ @Override
+ public TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset) {
+ checkMetadata();
+ TextPointer start = newPointer(startLine, startLineOffset);
+ TextPointer end = newPointer(endLine, endLineOffset);
+ return newRangeValidPointers(start, end, false);
+ }
+
+ @Override
+ public TextRange selectLine(int line) {
+ checkMetadata();
+ TextPointer startPointer = newPointer(line, 0);
+ TextPointer endPointer = newPointer(line, lineLength(line));
+ return newRangeValidPointers(startPointer, endPointer, true);
+ }
+
+ public void validate(TextRange range) {
+ checkMetadata();
+ checkValid(range.start(), "start pointer");
+ checkValid(range.end(), "end pointer");
+ }
+
+ /**
+ * Create Range from global offsets. Used for backward compatibility with older API.
+ */
+ public TextRange newRange(int startOffset, int endOffset) {
+ checkMetadata();
+ return newRangeValidPointers(newPointer(startOffset), newPointer(endOffset), false);
+ }
+
+ public TextPointer newPointer(int globalOffset) {
+ checkMetadata();
+ checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset);
+ checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset());
+ int line = findLine(globalOffset);
+ int startLineOffset = originalLineStartOffsets()[line - 1];
+ // In case the global offset is between \r and \n, move the pointer to a valid location
+ return new DefaultTextPointer(line, Math.min(globalOffset, originalLineEndOffsets()[line - 1]) - startLineOffset);
+ }
+
+ public DefaultInputFile setStatus(Status status) {
+ this.status = status;
+ return this;
+ }
+
+ public DefaultInputFile setCharset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ private void checkValid(TextPointer pointer, String owner) {
+ checkArgument(pointer.line() >= 1, "%s is not a valid line for a file", pointer.line());
+ checkArgument(pointer.line() <= this.metadata.lines(), "%s is not a valid line for %s. File %s has %s line(s)", pointer.line(), owner, this, metadata.lines());
+ checkArgument(pointer.lineOffset() >= 0, "%s is not a valid line offset for a file", pointer.lineOffset());
+ int lineLength = lineLength(pointer.line());
+ checkArgument(pointer.lineOffset() <= lineLength,
+ "%s is not a valid line offset for %s. File %s has %s character(s) at line %s", pointer.lineOffset(), owner, this, lineLength, pointer.line());
+ }
+
+ private int lineLength(int line) {
+ return originalLineEndOffsets()[line - 1] - originalLineStartOffsets()[line - 1];
+ }
+
+ private static TextRange newRangeValidPointers(TextPointer start, TextPointer end, boolean acceptEmptyRange) {
+ checkArgument(acceptEmptyRange ? (start.compareTo(end) <= 0) : (start.compareTo(end) < 0),
+ "Start pointer %s should be before end pointer %s", start, end);
+ return new DefaultTextRange(start, end);
+ }
+
+ private int findLine(int globalOffset) {
+ return Math.abs(Arrays.binarySearch(originalLineStartOffsets(), globalOffset) + 1);
+ }
+
+ public DefaultInputFile setMetadata(Metadata metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ if (this.getClass() != obj.getClass()) {
+ return false;
+ }
+
+ DefaultInputFile that = (DefaultInputFile) obj;
+ return this.getProjectRelativePath().equals(that.getProjectRelativePath());
+ }
+
+ @Override
+ public boolean isFile() {
+ return true;
+ }
+
+ @Override
+ public String filename() {
+ return indexedFile.filename();
+ }
+
+ @Override
+ public URI uri() {
+ return indexedFile.uri();
+ }
+
+ public void noSonarAt(Set<Integer> noSonarLines) {
+ if (this.noSonarLines == null) {
+ this.noSonarLines = new BitSet(lines());
+ }
+ noSonarLines.forEach(l -> this.noSonarLines.set(l - 1));
+ }
+
+ public boolean hasNoSonarAt(int line) {
+ if (this.noSonarLines == null) {
+ return false;
+ }
+ return this.noSonarLines.get(line - 1);
+ }
+
+ public boolean isIgnoreAllIssues() {
+ return ignoreAllIssues;
+ }
+
+ public void setIgnoreAllIssues(boolean ignoreAllIssues) {
+ this.ignoreAllIssues = ignoreAllIssues;
+ }
+
+ public void addIgnoreIssuesOnLineRanges(Collection<int[]> lineRanges) {
+ if (this.ignoreIssuesOnlineRanges == null) {
+ this.ignoreIssuesOnlineRanges = new ArrayList<>();
+ }
+ this.ignoreIssuesOnlineRanges.addAll(lineRanges);
+ }
+
+ public boolean isIgnoreAllIssuesOnLine(@Nullable Integer line) {
+ if (line == null || ignoreIssuesOnlineRanges == null) {
+ return false;
+ }
+ return ignoreIssuesOnlineRanges.stream().anyMatch(r -> r[0] <= line && line <= r[1]);
+ }
+
+ public void setExecutableLines(Set<Integer> executableLines) {
+ checkState(this.executableLines == null, "Executable lines have already been saved for file: {}", this.toString());
+ this.executableLines = new BitSet(lines());
+ executableLines.forEach(l -> this.executableLines.set(l - 1));
+ }
+
+ public Optional<Set<Integer>> getExecutableLines() {
+ if (this.executableLines == null) {
+ return Optional.empty();
+ }
+ return Optional.of(this.executableLines.stream().map(i -> i + 1).boxed().collect(Collectors.toSet()));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.scan.filesystem.PathResolver;
+
+import static org.sonar.api.impl.config.MultivalueProperty.parseAsCsv;
+
+@Immutable
+public class DefaultInputModule extends AbstractProjectOrModule implements InputModule {
+
+ private final List<Path> sourceDirsOrFiles;
+ private final List<Path> testDirsOrFiles;
+
+ /**
+ * For testing only!
+ */
+ public DefaultInputModule(ProjectDefinition definition) {
+ this(definition, 0);
+ }
+
+ public DefaultInputModule(ProjectDefinition definition, int scannerComponentId) {
+ super(definition, scannerComponentId);
+
+ this.sourceDirsOrFiles = initSources(definition, ProjectDefinition.SOURCES_PROPERTY);
+ this.testDirsOrFiles = initSources(definition, ProjectDefinition.TESTS_PROPERTY);
+ }
+
+ @CheckForNull
+ private List<Path> initSources(ProjectDefinition module, String propertyKey) {
+ if (!module.properties().containsKey(propertyKey)) {
+ return null;
+ }
+ List<Path> result = new ArrayList<>();
+ PathResolver pathResolver = new PathResolver();
+ String srcPropValue = module.properties().get(propertyKey);
+ if (srcPropValue != null) {
+ for (String sourcePath : parseAsCsv(propertyKey, srcPropValue)) {
+ File dirOrFile = pathResolver.relativeFile(getBaseDir().toFile(), sourcePath);
+ if (dirOrFile.exists()) {
+ result.add(dirOrFile.toPath());
+ }
+ }
+ }
+ return result;
+ }
+
+ public Optional<List<Path>> getSourceDirsOrFiles() {
+ return Optional.ofNullable(sourceDirsOrFiles);
+ }
+
+ public Optional<List<Path>> getTestDirsOrFiles() {
+ return Optional.ofNullable(testDirsOrFiles);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.scanner.fs.InputProject;
+
+@Immutable
+public class DefaultInputProject extends AbstractProjectOrModule implements InputProject {
+
+ /**
+ * For testing only!
+ */
+ public DefaultInputProject(ProjectDefinition definition) {
+ super(definition, 0);
+ }
+
+ public DefaultInputProject(ProjectDefinition definition, int scannerComponentId) {
+ super(definition, scannerComponentId);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import org.sonar.api.batch.fs.TextPointer;
+
+/**
+ * @since 5.2
+ */
+public class DefaultTextPointer implements TextPointer {
+
+ private final int line;
+ private final int lineOffset;
+
+ public DefaultTextPointer(int line, int lineOffset) {
+ this.line = line;
+ this.lineOffset = lineOffset;
+ }
+
+ @Override
+ public int line() {
+ return line;
+ }
+
+ @Override
+ public int lineOffset() {
+ return lineOffset;
+ }
+
+ @Override
+ public String toString() {
+ return "[line=" + line + ", lineOffset=" + lineOffset + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DefaultTextPointer)) {
+ return false;
+ }
+ DefaultTextPointer other = (DefaultTextPointer) obj;
+ return other.line == this.line && other.lineOffset == this.lineOffset;
+ }
+
+ @Override
+ public int hashCode() {
+ return 37 * this.line + lineOffset;
+ }
+
+ @Override
+ public int compareTo(TextPointer o) {
+ if (this.line == o.line()) {
+ return Integer.compare(this.lineOffset, o.lineOffset());
+ }
+ return Integer.compare(this.line, o.line());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import org.sonar.api.batch.fs.TextPointer;
+import org.sonar.api.batch.fs.TextRange;
+
+/**
+ * @since 5.2
+ */
+public class DefaultTextRange implements TextRange {
+
+ private final TextPointer start;
+ private final TextPointer end;
+
+ public DefaultTextRange(TextPointer start, TextPointer end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ @Override
+ public TextPointer start() {
+ return start;
+ }
+
+ @Override
+ public TextPointer end() {
+ return end;
+ }
+
+ @Override
+ public boolean overlap(TextRange another) {
+ // [A,B] and [C,D]
+ // B > C && D > A
+ return this.end.compareTo(another.start()) > 0 && another.end().compareTo(this.start) > 0;
+ }
+
+ @Override
+ public String toString() {
+ return "Range[from " + start + " to " + end + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof DefaultTextRange)) {
+ return false;
+ }
+ DefaultTextRange other = (DefaultTextRange) obj;
+ return start.equals(other.start) && end.equals(other.end);
+ }
+
+ @Override
+ public int hashCode() {
+ return start.hashCode() * 17 + end.hashCode();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.fs.charhandler.CharHandler;
+import org.sonar.api.impl.fs.charhandler.FileHashComputer;
+import org.sonar.api.impl.fs.charhandler.LineCounter;
+import org.sonar.api.impl.fs.charhandler.LineHashComputer;
+import org.sonar.api.impl.fs.charhandler.LineOffsetCounter;
+
+/**
+ * Computes hash of files. Ends of Lines are ignored, so files with
+ * same content but different EOL encoding have the same hash.
+ */
+@Immutable
+public class FileMetadata {
+ private static final char LINE_FEED = '\n';
+ private static final char CARRIAGE_RETURN = '\r';
+
+ /**
+ * Compute hash of a file ignoring line ends differences.
+ * Maximum performance is needed.
+ */
+ public Metadata readMetadata(InputStream stream, Charset encoding, String filePath, @Nullable CharHandler otherHandler) {
+ LineCounter lineCounter = new LineCounter(filePath, encoding);
+ FileHashComputer fileHashComputer = new FileHashComputer(filePath);
+ LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
+
+ if (otherHandler != null) {
+ CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter, otherHandler};
+ readFile(stream, encoding, filePath, handlers);
+ } else {
+ CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
+ readFile(stream, encoding, filePath, handlers);
+ }
+ return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(),
+ lineOffsetCounter.getOriginalLineEndOffsets(),
+ lineOffsetCounter.getLastValidOffset());
+ }
+
+ public Metadata readMetadata(InputStream stream, Charset encoding, String filePath) {
+ return readMetadata(stream, encoding, filePath, null);
+ }
+
+ /**
+ * For testing purpose
+ */
+ public Metadata readMetadata(Reader reader) {
+ LineCounter lineCounter = new LineCounter("fromString", StandardCharsets.UTF_16);
+ FileHashComputer fileHashComputer = new FileHashComputer("fromString");
+ LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
+ CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
+
+ try {
+ read(reader, handlers);
+ } catch (IOException e) {
+ throw new IllegalStateException("Should never occur", e);
+ }
+ return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(),
+ lineOffsetCounter.getOriginalLineEndOffsets(),
+ lineOffsetCounter.getLastValidOffset());
+ }
+
+ public static void readFile(InputStream stream, Charset encoding, String filePath, CharHandler[] handlers) {
+ try (Reader reader = new BufferedReader(new InputStreamReader(stream, encoding))) {
+ read(reader, handlers);
+ } catch (IOException e) {
+ throw new IllegalStateException(String.format("Fail to read file '%s' with encoding '%s'", filePath, encoding), e);
+ }
+ }
+
+ private static void read(Reader reader, CharHandler[] handlers) throws IOException {
+ char c;
+ int i = reader.read();
+ boolean afterCR = false;
+ while (i != -1) {
+ c = (char) i;
+ if (afterCR) {
+ for (CharHandler handler : handlers) {
+ if (c == CARRIAGE_RETURN) {
+ handler.newLine();
+ handler.handleAll(c);
+ } else if (c == LINE_FEED) {
+ handler.handleAll(c);
+ handler.newLine();
+ } else {
+ handler.newLine();
+ handler.handleIgnoreEoL(c);
+ handler.handleAll(c);
+ }
+ }
+ afterCR = c == CARRIAGE_RETURN;
+ } else if (c == LINE_FEED) {
+ for (CharHandler handler : handlers) {
+ handler.handleAll(c);
+ handler.newLine();
+ }
+ } else if (c == CARRIAGE_RETURN) {
+ afterCR = true;
+ for (CharHandler handler : handlers) {
+ handler.handleAll(c);
+ }
+ } else {
+ for (CharHandler handler : handlers) {
+ handler.handleIgnoreEoL(c);
+ handler.handleAll(c);
+ }
+ }
+ i = reader.read();
+ }
+ for (CharHandler handler : handlers) {
+ if (afterCR) {
+ handler.newLine();
+ }
+ handler.eof();
+ }
+ }
+
+ @FunctionalInterface
+ public interface LineHashConsumer {
+ void consume(int lineIdx, @Nullable byte[] hash);
+ }
+
+ /**
+ * Compute a MD5 hash of each line of the file after removing of all blank chars
+ */
+ public static void computeLineHashesForIssueTracking(InputFile f, LineHashConsumer consumer) {
+ try {
+ readFile(f.inputStream(), f.charset(), f.absolutePath(), new CharHandler[] {new LineHashComputer(consumer, f.file())});
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to compute line hashes for " + f.absolutePath(), e);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.util.Arrays;
+
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+public class Metadata {
+ private final int lines;
+ private final int nonBlankLines;
+ private final String hash;
+ private final int[] originalLineStartOffsets;
+ private final int[] originalLineEndOffsets;
+ private final int lastValidOffset;
+
+ public Metadata(int lines, int nonBlankLines, String hash, int[] originalLineStartOffsets, int[] originalLineEndOffsets, int lastValidOffset) {
+ this.lines = lines;
+ this.nonBlankLines = nonBlankLines;
+ this.hash = hash;
+ this.originalLineStartOffsets = Arrays.copyOf(originalLineStartOffsets, originalLineStartOffsets.length);
+ this.originalLineEndOffsets = Arrays.copyOf(originalLineEndOffsets, originalLineEndOffsets.length);
+ this.lastValidOffset = lastValidOffset;
+ }
+
+ public int lines() {
+ return lines;
+ }
+
+ public int nonBlankLines() {
+ return nonBlankLines;
+ }
+
+ public String hash() {
+ return hash;
+ }
+
+ public int[] originalLineStartOffsets() {
+ return originalLineStartOffsets;
+ }
+
+ public int[] originalLineEndOffsets() {
+ return originalLineEndOffsets;
+ }
+
+ public int lastValidOffset() {
+ return lastValidOffset;
+ }
+
+ public boolean isEmpty() {
+ return lastValidOffset == 0;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.nio.file.Path;
+import javax.annotation.concurrent.ThreadSafe;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.utils.PathUtils;
+import org.sonar.api.utils.WildcardPattern;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+@ThreadSafe
+public abstract class PathPattern {
+
+ private static final Logger LOG = Loggers.get(PathPattern.class);
+
+ /**
+ * @deprecated since 6.6
+ */
+ @Deprecated
+ private static final String ABSOLUTE_PATH_PATTERN_PREFIX = "file:";
+ final WildcardPattern pattern;
+
+ PathPattern(String pattern) {
+ this.pattern = WildcardPattern.create(pattern);
+ }
+
+ public abstract boolean match(Path absolutePath, Path relativePath);
+
+ public abstract boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension);
+
+ public static PathPattern create(String s) {
+ String trimmed = StringUtils.trim(s);
+ if (StringUtils.startsWithIgnoreCase(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX)) {
+ LOG.warn("Using absolute path pattern is deprecated. Please use relative path instead of '" + trimmed + "'");
+ return new AbsolutePathPattern(StringUtils.substring(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX.length()));
+ }
+ return new RelativePathPattern(trimmed);
+ }
+
+ public static PathPattern[] create(String[] s) {
+ PathPattern[] result = new PathPattern[s.length];
+ for (int i = 0; i < s.length; i++) {
+ result[i] = create(s[i]);
+ }
+ return result;
+ }
+
+ /**
+ * @deprecated since 6.6
+ */
+ @Deprecated
+ private static class AbsolutePathPattern extends PathPattern {
+ private AbsolutePathPattern(String pattern) {
+ super(pattern);
+ }
+
+ @Override
+ public boolean match(Path absolutePath, Path relativePath) {
+ return match(absolutePath, relativePath, true);
+ }
+
+ @Override
+ public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
+ String path = PathUtils.sanitize(absolutePath.toString());
+ if (!caseSensitiveFileExtension) {
+ String extension = sanitizeExtension(FilenameUtils.getExtension(path));
+ if (StringUtils.isNotBlank(extension)) {
+ path = StringUtils.removeEndIgnoreCase(path, extension);
+ path = path + extension;
+ }
+ }
+ return pattern.match(path);
+ }
+
+ @Override
+ public String toString() {
+ return ABSOLUTE_PATH_PATTERN_PREFIX + pattern.toString();
+ }
+ }
+
+ /**
+ * Path relative to module basedir
+ */
+ private static class RelativePathPattern extends PathPattern {
+ private RelativePathPattern(String pattern) {
+ super(pattern);
+ }
+
+ @Override
+ public boolean match(Path absolutePath, Path relativePath) {
+ return match(absolutePath, relativePath, true);
+ }
+
+ @Override
+ public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
+ String path = PathUtils.sanitize(relativePath.toString());
+ if (!caseSensitiveFileExtension) {
+ String extension = sanitizeExtension(FilenameUtils.getExtension(path));
+ if (StringUtils.isNotBlank(extension)) {
+ path = StringUtils.removeEndIgnoreCase(path, extension);
+ path = path + extension;
+ }
+ }
+ return path != null && pattern.match(path);
+ }
+
+ @Override
+ public String toString() {
+ return pattern.toString();
+ }
+ }
+
+ static String sanitizeExtension(String suffix) {
+ return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * A shared, mutable object in the project container.
+ * It's used during the execution of sensors to decide whether
+ * sensors should be executed once for the entire project, or per-module.
+ * It is also injected into each InputFile to change the behavior of {@link InputFile#relativePath()}
+ */
+public class SensorStrategy {
+
+ private boolean global = true;
+
+ public boolean isGlobal() {
+ return global;
+ }
+
+ public void setGlobal(boolean global) {
+ this.global = global;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * Intended to be used in unit tests that need to create {@link InputFile}s.
+ * An InputFile is unambiguously identified by a <b>module key</b> and a <b>relative path</b>, so these parameters are mandatory.
+ * <p>
+ * A module base directory is only needed to construct absolute paths.
+ * <p>
+ * Examples of usage of the constructors:
+ *
+ * <pre>
+ * InputFile file1 = TestInputFileBuilder.create("module1", "myfile.java").build();
+ * InputFile file2 = TestInputFileBuilder.create("", fs.baseDir(), myfile).build();
+ * </pre>
+ * <p>
+ * file1 will have the "module1" as both module key and module base directory.
+ * file2 has an empty string as module key, and a relative path which is the path from the filesystem base directory to myfile.
+ *
+ * @since 6.3
+ */
+public class TestInputFileBuilder {
+ private static int batchId = 1;
+
+ private final int id;
+ private final String relativePath;
+ private final String projectKey;
+ @CheckForNull
+ private Path projectBaseDir;
+ private Path moduleBaseDir;
+ private String language;
+ private InputFile.Type type = InputFile.Type.MAIN;
+ private InputFile.Status status;
+ private int lines = -1;
+ private Charset charset;
+ private String hash;
+ private int nonBlankLines;
+ private int[] originalLineStartOffsets = new int[0];
+ private int[] originalLineEndOffsets = new int[0];
+ private int lastValidOffset = -1;
+ private boolean publish = true;
+ private String contents;
+
+ /**
+ * Create a InputFile identified by the given project key and relative path.
+ */
+ public TestInputFileBuilder(String projectKey, String relativePath) {
+ this(projectKey, relativePath, batchId++);
+ }
+
+ /**
+ * Create a InputFile with a given module key and module base directory.
+ * The relative path is generated comparing the file path to the module base directory.
+ * filePath must point to a file that is within the module base directory.
+ */
+ public TestInputFileBuilder(String projectKey, File moduleBaseDir, File filePath) {
+ String relativePath = moduleBaseDir.toPath().relativize(filePath.toPath()).toString();
+ this.projectKey = projectKey;
+ setModuleBaseDir(moduleBaseDir.toPath());
+ this.relativePath = PathUtils.sanitize(relativePath);
+ this.id = batchId++;
+ }
+
+ public TestInputFileBuilder(String projectKey, String relativePath, int id) {
+ this.projectKey = projectKey;
+ setModuleBaseDir(Paths.get(projectKey));
+ this.relativePath = PathUtils.sanitize(relativePath);
+ this.id = id;
+ }
+
+ public static TestInputFileBuilder create(String moduleKey, File moduleBaseDir, File filePath) {
+ return new TestInputFileBuilder(moduleKey, moduleBaseDir, filePath);
+ }
+
+ public static TestInputFileBuilder create(String moduleKey, String relativePath) {
+ return new TestInputFileBuilder(moduleKey, relativePath);
+ }
+
+ public static int nextBatchId() {
+ return batchId++;
+ }
+
+ public TestInputFileBuilder setProjectBaseDir(Path projectBaseDir) {
+ this.projectBaseDir = normalize(projectBaseDir);
+ return this;
+ }
+
+ public TestInputFileBuilder setModuleBaseDir(Path moduleBaseDir) {
+ this.moduleBaseDir = normalize(moduleBaseDir);
+ return this;
+ }
+
+ private static Path normalize(Path path) {
+ try {
+ return path.normalize().toRealPath(LinkOption.NOFOLLOW_LINKS);
+ } catch (IOException e) {
+ return path.normalize();
+ }
+ }
+
+ public TestInputFileBuilder setLanguage(@Nullable String language) {
+ this.language = language;
+ return this;
+ }
+
+ public TestInputFileBuilder setType(InputFile.Type type) {
+ this.type = type;
+ return this;
+ }
+
+ public TestInputFileBuilder setStatus(InputFile.Status status) {
+ this.status = status;
+ return this;
+ }
+
+ public TestInputFileBuilder setLines(int lines) {
+ this.lines = lines;
+ return this;
+ }
+
+ public TestInputFileBuilder setCharset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ public TestInputFileBuilder setHash(String hash) {
+ this.hash = hash;
+ return this;
+ }
+
+ /**
+ * Set contents of the file and calculates metadata from it.
+ * The contents will be returned by {@link InputFile#contents()} and {@link InputFile#inputStream()} and can be
+ * inconsistent with the actual physical file pointed by {@link InputFile#path()}, {@link InputFile#absolutePath()}, etc.
+ */
+ public TestInputFileBuilder setContents(String content) {
+ this.contents = content;
+ initMetadata(content);
+ return this;
+ }
+
+ public TestInputFileBuilder setNonBlankLines(int nonBlankLines) {
+ this.nonBlankLines = nonBlankLines;
+ return this;
+ }
+
+ public TestInputFileBuilder setLastValidOffset(int lastValidOffset) {
+ this.lastValidOffset = lastValidOffset;
+ return this;
+ }
+
+ public TestInputFileBuilder setOriginalLineStartOffsets(int[] originalLineStartOffsets) {
+ this.originalLineStartOffsets = originalLineStartOffsets;
+ return this;
+ }
+
+ public TestInputFileBuilder setOriginalLineEndOffsets(int[] originalLineEndOffsets) {
+ this.originalLineEndOffsets = originalLineEndOffsets;
+ return this;
+ }
+
+ public TestInputFileBuilder setPublish(boolean publish) {
+ this.publish = publish;
+ return this;
+ }
+
+ public TestInputFileBuilder setMetadata(Metadata metadata) {
+ this.setLines(metadata.lines());
+ this.setLastValidOffset(metadata.lastValidOffset());
+ this.setNonBlankLines(metadata.nonBlankLines());
+ this.setHash(metadata.hash());
+ this.setOriginalLineStartOffsets(metadata.originalLineStartOffsets());
+ this.setOriginalLineEndOffsets(metadata.originalLineEndOffsets());
+ return this;
+ }
+
+ public TestInputFileBuilder initMetadata(String content) {
+ return setMetadata(new FileMetadata().readMetadata(new StringReader(content)));
+ }
+
+ public DefaultInputFile build() {
+ Path absolutePath = moduleBaseDir.resolve(relativePath);
+ if (projectBaseDir == null) {
+ projectBaseDir = moduleBaseDir;
+ }
+ String projectRelativePath = projectBaseDir.relativize(absolutePath).toString();
+ DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, projectKey, projectRelativePath, relativePath, type, language, id, new SensorStrategy());
+ DefaultInputFile inputFile = new DefaultInputFile(indexedFile,
+ f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineStartOffsets, originalLineEndOffsets, lastValidOffset)),
+ contents);
+ inputFile.setStatus(status);
+ inputFile.setCharset(charset);
+ inputFile.setPublished(publish);
+ return inputFile;
+ }
+
+ public static DefaultInputModule newDefaultInputModule(String moduleKey, File baseDir) {
+ ProjectDefinition definition = ProjectDefinition.create()
+ .setKey(moduleKey)
+ .setBaseDir(baseDir)
+ .setWorkDir(new File(baseDir, ".sonar"));
+ return newDefaultInputModule(definition);
+ }
+
+ public static DefaultInputModule newDefaultInputModule(ProjectDefinition projectDefinition) {
+ return new DefaultInputModule(projectDefinition, TestInputFileBuilder.nextBatchId());
+ }
+
+ public static DefaultInputModule newDefaultInputModule(AbstractProjectOrModule parent, String key) throws IOException {
+ Path basedir = parent.getBaseDir().resolve(key);
+ Files.createDirectory(basedir);
+ return newDefaultInputModule(key, basedir.toFile());
+ }
+
+ public static DefaultInputProject newDefaultInputProject(String projectKey, File baseDir) {
+ ProjectDefinition definition = ProjectDefinition.create()
+ .setKey(projectKey)
+ .setBaseDir(baseDir)
+ .setWorkDir(new File(baseDir, ".sonar"));
+ return newDefaultInputProject(definition);
+ }
+
+ public static DefaultInputProject newDefaultInputProject(ProjectDefinition projectDefinition) {
+ return new DefaultInputProject(projectDefinition, TestInputFileBuilder.nextBatchId());
+ }
+
+ public static DefaultInputProject newDefaultInputProject(String key, Path baseDir) throws IOException {
+ Files.createDirectory(baseDir);
+ return newDefaultInputProject(key, baseDir.toFile());
+ }
+
+ public static DefaultInputDir newDefaultInputDir(AbstractProjectOrModule module, String relativePath) throws IOException {
+ Path basedir = module.getBaseDir().resolve(relativePath);
+ Files.createDirectory(basedir);
+ return new DefaultInputDir(module.key(), relativePath)
+ .setModuleBaseDir(module.getBaseDir());
+ }
+
+ public static DefaultInputFile newDefaultInputFile(Path projectBaseDir, AbstractProjectOrModule module, String relativePath) {
+ return new TestInputFileBuilder(module.key(), relativePath)
+ .setStatus(InputFile.Status.SAME)
+ .setProjectBaseDir(projectBaseDir)
+ .setModuleBaseDir(module.getBaseDir())
+ .build();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+public abstract class CharHandler {
+
+ public void handleAll(char c) {
+ }
+
+ public void handleIgnoreEoL(char c) {
+ }
+
+ public void newLine() {
+ }
+
+ public void eof() {
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+
+public class FileHashComputer extends CharHandler {
+ private static final char LINE_FEED = '\n';
+
+
+ private MessageDigest globalMd5Digest = DigestUtils.getMd5Digest();
+ private StringBuilder sb = new StringBuilder();
+ private final CharsetEncoder encoder;
+ private final String filePath;
+
+ public FileHashComputer(String filePath) {
+ encoder = StandardCharsets.UTF_8.newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.filePath = filePath;
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ sb.append(c);
+ }
+
+ @Override
+ public void newLine() {
+ sb.append(LINE_FEED);
+ processBuffer();
+ sb.setLength(0);
+ }
+
+ @Override
+ public void eof() {
+ if (sb.length() > 0) {
+ processBuffer();
+ }
+ }
+
+ private void processBuffer() {
+ try {
+ if (sb.length() > 0) {
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
+ globalMd5Digest.update(encoded.array(), 0, encoded.limit());
+ }
+ } catch (CharacterCodingException e) {
+ throw new IllegalStateException("Error encoding line hash in file: " + filePath, e);
+ }
+ }
+
+ public String getHash() {
+ return Hex.encodeHexString(globalMd5Digest.digest());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Specialization of {@link java.util.ArrayList} to create a list of int (only append elements) and then produce an int[].
+ */
+class IntArrayList {
+
+ /**
+ * Default initial capacity.
+ */
+ private static final int DEFAULT_CAPACITY = 10;
+
+ /**
+ * Shared empty array instance used for default sized empty instances. We
+ * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
+ * first element is added.
+ */
+ private static final int[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
+
+ /**
+ * The array buffer into which the elements of the ArrayList are stored.
+ * The capacity of the IntArrayList is the length of this array buffer. Any
+ * empty IntArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
+ * will be expanded to DEFAULT_CAPACITY when the first element is added.
+ */
+ private int[] elementData;
+
+ /**
+ * The size of the IntArrayList (the number of elements it contains).
+ */
+ private int size;
+
+ /**
+ * Constructs an empty list with an initial capacity of ten.
+ */
+ public IntArrayList() {
+ this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
+ }
+
+ /**
+ * Trims the capacity of this <tt>IntArrayList</tt> instance to be the
+ * list's current size and return the internal array. An application can use this operation to minimize
+ * the storage of an <tt>IntArrayList</tt> instance.
+ */
+ public int[] trimAndGet() {
+ if (size < elementData.length) {
+ elementData = Arrays.copyOf(elementData, size);
+ }
+ return elementData;
+ }
+
+ private void ensureCapacityInternal(int minCapacity) {
+ int capacity = minCapacity;
+ if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+ capacity = Math.max(DEFAULT_CAPACITY, minCapacity);
+ }
+
+ ensureExplicitCapacity(capacity);
+ }
+
+ private void ensureExplicitCapacity(int minCapacity) {
+ if (minCapacity - elementData.length > 0) {
+ grow(minCapacity);
+ }
+ }
+
+ /**
+ * Increases the capacity to ensure that it can hold at least the
+ * number of elements specified by the minimum capacity argument.
+ *
+ * @param minCapacity the desired minimum capacity
+ */
+ private void grow(int minCapacity) {
+ int oldCapacity = elementData.length;
+ int newCapacity = oldCapacity + (oldCapacity >> 1);
+ if (newCapacity - minCapacity < 0) {
+ newCapacity = minCapacity;
+ }
+ elementData = Arrays.copyOf(elementData, newCapacity);
+ }
+
+ /**
+ * Appends the specified element to the end of this list.
+ *
+ * @param e element to be appended to this list
+ * @return <tt>true</tt> (as specified by {@link Collection#add})
+ */
+ public boolean add(int e) {
+ ensureCapacityInternal(size + 1);
+ elementData[size] = e;
+ size++;
+ return true;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+import java.nio.charset.Charset;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public class LineCounter extends CharHandler {
+ private static final Logger LOG = Loggers.get(LineCounter.class);
+
+ private int lines = 1;
+ private int nonBlankLines = 0;
+ private boolean blankLine = true;
+ boolean alreadyLoggedInvalidCharacter = false;
+ private final String filePath;
+ private final Charset encoding;
+
+ public LineCounter(String filePath, Charset encoding) {
+ this.filePath = filePath;
+ this.encoding = encoding;
+ }
+
+ @Override
+ public void handleAll(char c) {
+ if (!alreadyLoggedInvalidCharacter && c == '\ufffd') {
+ LOG.warn("Invalid character encountered in file {} at line {} for encoding {}. Please fix file content or configure the encoding to be used using property '{}'.", filePath,
+ lines, encoding, CoreProperties.ENCODING_PROPERTY);
+ alreadyLoggedInvalidCharacter = true;
+ }
+ }
+
+ @Override
+ public void newLine() {
+ lines++;
+ if (!blankLine) {
+ nonBlankLines++;
+ }
+ blankLine = true;
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ if (!Character.isWhitespace(c)) {
+ blankLine = false;
+ }
+ }
+
+ @Override
+ public void eof() {
+ if (!blankLine) {
+ nonBlankLines++;
+ }
+ }
+
+ public int lines() {
+ return lines;
+ }
+
+ public int nonBlankLines() {
+ return nonBlankLines;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.sonar.api.impl.fs.FileMetadata;
+
+public class LineHashComputer extends CharHandler {
+ private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
+ private final CharsetEncoder encoder;
+ private final StringBuilder sb = new StringBuilder();
+ private final FileMetadata.LineHashConsumer consumer;
+ private final File file;
+ private int line = 1;
+
+ public LineHashComputer(FileMetadata.LineHashConsumer consumer, File f) {
+ this.consumer = consumer;
+ this.file = f;
+ this.encoder = StandardCharsets.UTF_8.newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ if (!Character.isWhitespace(c)) {
+ sb.append(c);
+ }
+ }
+
+ @Override
+ public void newLine() {
+ processBuffer();
+ sb.setLength(0);
+ line++;
+ }
+
+ @Override
+ public void eof() {
+ if (this.line > 0) {
+ processBuffer();
+ }
+ }
+
+ private void processBuffer() {
+ try {
+ if (sb.length() > 0) {
+ ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
+ lineMd5Digest.update(encoded.array(), 0, encoded.limit());
+ consumer.consume(line, lineMd5Digest.digest());
+ }
+ } catch (CharacterCodingException e) {
+ throw new IllegalStateException("Error encoding line hash in file: " + file.getAbsolutePath(), e);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+public class LineOffsetCounter extends CharHandler {
+ private long currentOriginalLineStartOffset = 0;
+ private long currentOriginalLineEndOffset = 0;
+ private final IntArrayList originalLineStartOffsets = new IntArrayList();
+ private final IntArrayList originalLineEndOffsets = new IntArrayList();
+ private long lastValidOffset = 0;
+
+ public LineOffsetCounter() {
+ originalLineStartOffsets.add(0);
+ }
+
+ @Override
+ public void handleAll(char c) {
+ currentOriginalLineStartOffset++;
+ }
+
+ @Override
+ public void handleIgnoreEoL(char c) {
+ currentOriginalLineEndOffset++;
+ }
+
+ @Override
+ public void newLine() {
+ if (currentOriginalLineStartOffset > Integer.MAX_VALUE) {
+ throw new IllegalStateException("File is too big: " + currentOriginalLineStartOffset);
+ }
+ originalLineStartOffsets.add((int) currentOriginalLineStartOffset);
+ originalLineEndOffsets.add((int) currentOriginalLineEndOffset);
+ currentOriginalLineEndOffset = currentOriginalLineStartOffset;
+ }
+
+ @Override
+ public void eof() {
+ originalLineEndOffsets.add((int) currentOriginalLineEndOffset);
+ lastValidOffset = currentOriginalLineStartOffset;
+ }
+
+ public int[] getOriginalLineStartOffsets() {
+ return originalLineStartOffsets.trimAndGet();
+ }
+
+ public int[] getOriginalLineEndOffsets() {
+ return originalLineEndOffsets.trimAndGet();
+ }
+
+ public int getLastValidOffset() {
+ if (lastValidOffset > Integer.MAX_VALUE) {
+ throw new IllegalStateException("File is too big: " + lastValidOffset);
+ }
+ return (int) lastValidOffset;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.fs.charhandler;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.fs;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * @since 4.2
+ */
+class AbsolutePathPredicate extends AbstractFilePredicate {
+
+ private final String path;
+ private final Path baseDir;
+
+ AbsolutePathPredicate(String path, Path baseDir) {
+ this.baseDir = baseDir;
+ this.path = PathUtils.sanitize(path);
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return path.equals(f.absolutePath());
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ String relative = PathUtils.sanitize(new PathResolver().relativePath(baseDir.toFile(), new File(path)));
+ if (relative == null) {
+ return Collections.emptyList();
+ }
+ InputFile f = index.inputFile(relative);
+ return f != null ? Arrays.asList(f) : Collections.<InputFile>emptyList();
+ }
+
+ @Override
+ public int priority() {
+ return USE_INDEX;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.stream.StreamSupport;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * Partial implementation of {@link OptimizedFilePredicate}.
+ * @since 5.1
+ */
+public abstract class AbstractFilePredicate implements OptimizedFilePredicate {
+
+ protected static final int DEFAULT_PRIORITY = 10;
+ protected static final int USE_INDEX = 20;
+
+ @Override
+ public Iterable<InputFile> filter(Iterable<InputFile> target) {
+ return () -> StreamSupport.stream(target.spliterator(), false)
+ .filter(this::apply)
+ .iterator();
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ return filter(index.inputFiles());
+ }
+
+ @Override
+ public int priority() {
+ return DEFAULT_PRIORITY;
+ }
+
+ @Override
+ public final int compareTo(OptimizedFilePredicate o) {
+ return o.priority() - priority();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @since 4.2
+ */
+class AndPredicate extends AbstractFilePredicate implements OperatorPredicate {
+
+ private final List<OptimizedFilePredicate> predicates = new ArrayList<>();
+
+ private AndPredicate() {
+ }
+
+ public static FilePredicate create(Collection<FilePredicate> predicates) {
+ if (predicates.isEmpty()) {
+ return TruePredicate.TRUE;
+ }
+ AndPredicate result = new AndPredicate();
+ for (FilePredicate filePredicate : predicates) {
+ if (filePredicate == TruePredicate.TRUE) {
+ continue;
+ } else if (filePredicate == FalsePredicate.FALSE) {
+ return FalsePredicate.FALSE;
+ } else if (filePredicate instanceof AndPredicate) {
+ result.predicates.addAll(((AndPredicate) filePredicate).predicates);
+ } else {
+ result.predicates.add(OptimizedFilePredicateAdapter.create(filePredicate));
+ }
+ }
+ Collections.sort(result.predicates);
+ return result;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ for (OptimizedFilePredicate predicate : predicates) {
+ if (!predicate.apply(f)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Iterable<InputFile> filter(Iterable<InputFile> target) {
+ Iterable<InputFile> result = target;
+ for (OptimizedFilePredicate predicate : predicates) {
+ result = predicate.filter(result);
+ }
+ return result;
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ if (predicates.isEmpty()) {
+ return index.inputFiles();
+ }
+ // Optimization, use get on first predicate then filter with next predicates
+ Iterable<InputFile> result = predicates.get(0).get(index);
+ for (int i = 1; i < predicates.size(); i++) {
+ result = predicates.get(i).filter(result);
+ }
+ return result;
+ }
+
+ Collection<OptimizedFilePredicate> predicates() {
+ return predicates;
+ }
+
+ @Override
+ public List<FilePredicate> operands() {
+ return predicates.stream().map(p -> (FilePredicate) p).collect(toList());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Status;
+import org.sonar.api.impl.fs.PathPattern;
+
+/**
+ * Factory of {@link FilePredicate}
+ *
+ * @since 4.2
+ */
+public class DefaultFilePredicates implements FilePredicates {
+
+ private final Path baseDir;
+
+ /**
+ * Client code should use {@link org.sonar.api.batch.fs.FileSystem#predicates()} to get an instance
+ */
+ public DefaultFilePredicates(Path baseDir) {
+ this.baseDir = baseDir;
+ }
+
+ /**
+ * Returns a predicate that always evaluates to true
+ */
+ @Override
+ public FilePredicate all() {
+ return TruePredicate.TRUE;
+ }
+
+ /**
+ * Returns a predicate that always evaluates to false
+ */
+ @Override
+ public FilePredicate none() {
+ return FalsePredicate.FALSE;
+ }
+
+ @Override
+ public FilePredicate hasAbsolutePath(String s) {
+ return new AbsolutePathPredicate(s, baseDir);
+ }
+
+ /**
+ * non-normalized path and Windows-style path are supported
+ */
+ @Override
+ public FilePredicate hasRelativePath(String s) {
+ return new RelativePathPredicate(s);
+ }
+
+ @Override
+ public FilePredicate hasFilename(String s) {
+ return new FilenamePredicate(s);
+ }
+
+ @Override
+ public FilePredicate hasExtension(String s) {
+ return new FileExtensionPredicate(s);
+ }
+
+ @Override
+ public FilePredicate hasURI(URI uri) {
+ return new URIPredicate(uri, baseDir);
+ }
+
+ @Override
+ public FilePredicate matchesPathPattern(String inclusionPattern) {
+ return new PathPatternPredicate(PathPattern.create(inclusionPattern));
+ }
+
+ @Override
+ public FilePredicate matchesPathPatterns(String[] inclusionPatterns) {
+ if (inclusionPatterns.length == 0) {
+ return TruePredicate.TRUE;
+ }
+ FilePredicate[] predicates = new FilePredicate[inclusionPatterns.length];
+ for (int i = 0; i < inclusionPatterns.length; i++) {
+ predicates[i] = new PathPatternPredicate(PathPattern.create(inclusionPatterns[i]));
+ }
+ return or(predicates);
+ }
+
+ @Override
+ public FilePredicate doesNotMatchPathPattern(String exclusionPattern) {
+ return not(matchesPathPattern(exclusionPattern));
+ }
+
+ @Override
+ public FilePredicate doesNotMatchPathPatterns(String[] exclusionPatterns) {
+ if (exclusionPatterns.length == 0) {
+ return TruePredicate.TRUE;
+ }
+ return not(matchesPathPatterns(exclusionPatterns));
+ }
+
+ @Override
+ public FilePredicate hasPath(String s) {
+ File file = new File(s);
+ if (file.isAbsolute()) {
+ return hasAbsolutePath(s);
+ }
+ return hasRelativePath(s);
+ }
+
+ @Override
+ public FilePredicate is(File ioFile) {
+ if (ioFile.isAbsolute()) {
+ return hasAbsolutePath(ioFile.getAbsolutePath());
+ }
+ return hasRelativePath(ioFile.getPath());
+ }
+
+ @Override
+ public FilePredicate hasLanguage(String language) {
+ return new LanguagePredicate(language);
+ }
+
+ @Override
+ public FilePredicate hasLanguages(Collection<String> languages) {
+ List<FilePredicate> list = new ArrayList<>();
+ for (String language : languages) {
+ list.add(hasLanguage(language));
+ }
+ return or(list);
+ }
+
+ @Override
+ public FilePredicate hasLanguages(String... languages) {
+ List<FilePredicate> list = new ArrayList<>();
+ for (String language : languages) {
+ list.add(hasLanguage(language));
+ }
+ return or(list);
+ }
+
+ @Override
+ public FilePredicate hasType(InputFile.Type type) {
+ return new TypePredicate(type);
+ }
+
+ @Override
+ public FilePredicate not(FilePredicate p) {
+ return new NotPredicate(p);
+ }
+
+ @Override
+ public FilePredicate or(Collection<FilePredicate> or) {
+ return OrPredicate.create(or);
+ }
+
+ @Override
+ public FilePredicate or(FilePredicate... or) {
+ return OrPredicate.create(Arrays.asList(or));
+ }
+
+ @Override
+ public FilePredicate or(FilePredicate first, FilePredicate second) {
+ return OrPredicate.create(Arrays.asList(first, second));
+ }
+
+ @Override
+ public FilePredicate and(Collection<FilePredicate> and) {
+ return AndPredicate.create(and);
+ }
+
+ @Override
+ public FilePredicate and(FilePredicate... and) {
+ return AndPredicate.create(Arrays.asList(and));
+ }
+
+ @Override
+ public FilePredicate and(FilePredicate first, FilePredicate second) {
+ return AndPredicate.create(Arrays.asList(first, second));
+ }
+
+ @Override
+ public FilePredicate hasStatus(Status status) {
+ return new StatusPredicate(status);
+ }
+
+ @Override
+ public FilePredicate hasAnyStatus() {
+ return new StatusPredicate(null);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.Collections;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+
+class FalsePredicate extends AbstractFilePredicate {
+
+ static final FilePredicate FALSE = new FalsePredicate();
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return false;
+ }
+
+ @Override
+ public Iterable<InputFile> filter(Iterable<InputFile> target) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ return Collections.emptyList();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.Locale;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 6.3
+ */
+public class FileExtensionPredicate extends AbstractFilePredicate {
+
+ private final String extension;
+
+ public FileExtensionPredicate(String extension) {
+ this.extension = lowercase(extension);
+ }
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return extension.equals(getExtension(inputFile));
+ }
+
+ @Override
+ public Iterable<InputFile> get(FileSystem.Index index) {
+ return index.getFilesByExtension(extension);
+ }
+
+ public static String getExtension(InputFile inputFile) {
+ return getExtension(inputFile.filename());
+ }
+
+ static String getExtension(String name) {
+ int index = name.lastIndexOf('.');
+ if (index < 0) {
+ return "";
+ }
+ return lowercase(name.substring(index + 1));
+ }
+
+ private static String lowercase(String extension) {
+ return extension.toLowerCase(Locale.ENGLISH);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 6.3
+ */
+public class FilenamePredicate extends AbstractFilePredicate {
+ private final String filename;
+
+ public FilenamePredicate(String filename) {
+ this.filename = filename;
+ }
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return filename.equals(inputFile.filename());
+ }
+
+ @Override
+ public Iterable<InputFile> get(FileSystem.Index index) {
+ return index.getFilesByName(filename);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 4.2
+ */
+class LanguagePredicate extends AbstractFilePredicate {
+ private final String language;
+
+ LanguagePredicate(String language) {
+ this.language = language;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return language.equals(f.language());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.Arrays;
+import java.util.List;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 4.2
+ */
+class NotPredicate extends AbstractFilePredicate implements OperatorPredicate {
+
+ private final FilePredicate predicate;
+
+ NotPredicate(FilePredicate predicate) {
+ this.predicate = predicate;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return !predicate.apply(f);
+ }
+
+ @Override
+ public List<FilePredicate> operands() {
+ return Arrays.asList(predicate);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.List;
+import org.sonar.api.batch.fs.FilePredicate;
+
+/**
+ * A predicate that associate other predicates
+ */
+public interface OperatorPredicate extends FilePredicate {
+
+ List<FilePredicate> operands();
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * Optimized version of FilePredicate allowing to speed up query by looking at InputFile by index.
+ */
+public interface OptimizedFilePredicate extends FilePredicate, Comparable<OptimizedFilePredicate> {
+
+ /**
+ * Filter provided files to keep only the ones that are valid for this predicate
+ */
+ Iterable<InputFile> filter(Iterable<InputFile> inputFiles);
+
+ /**
+ * Get all files that are valid for this predicate.
+ */
+ Iterable<InputFile> get(FileSystem.Index index);
+
+ /**
+ * For optimization. FilePredicates will be applied in priority order. For example when doing
+ * p.and(p1, p2, p3) then p1, p2 and p3 will be applied according to their priority value. Higher priority value
+ * are applied first.
+ * Assign a high priority when the predicate will likely highly reduce the set of InputFiles to filter. Also
+ * {@link RelativePathPredicate} and AbsolutePathPredicate have a high priority since they are using cache index.
+ */
+ int priority();
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputFile;
+
+public class OptimizedFilePredicateAdapter extends AbstractFilePredicate {
+
+ private FilePredicate unoptimizedPredicate;
+
+ private OptimizedFilePredicateAdapter(FilePredicate unoptimizedPredicate) {
+ this.unoptimizedPredicate = unoptimizedPredicate;
+ }
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return unoptimizedPredicate.apply(inputFile);
+ }
+
+ public static OptimizedFilePredicate create(FilePredicate predicate) {
+ if (predicate instanceof OptimizedFilePredicate) {
+ return (OptimizedFilePredicate) predicate;
+ } else {
+ return new OptimizedFilePredicateAdapter(predicate);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 4.2
+ */
+class OrPredicate extends AbstractFilePredicate implements OperatorPredicate {
+
+ private final List<FilePredicate> predicates = new ArrayList<>();
+
+ private OrPredicate() {
+ }
+
+ public static FilePredicate create(Collection<FilePredicate> predicates) {
+ if (predicates.isEmpty()) {
+ return TruePredicate.TRUE;
+ }
+ OrPredicate result = new OrPredicate();
+ for (FilePredicate filePredicate : predicates) {
+ if (filePredicate == TruePredicate.TRUE) {
+ return TruePredicate.TRUE;
+ } else if (filePredicate == FalsePredicate.FALSE) {
+ continue;
+ } else if (filePredicate instanceof OrPredicate) {
+ result.predicates.addAll(((OrPredicate) filePredicate).predicates);
+ } else {
+ result.predicates.add(filePredicate);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ for (FilePredicate predicate : predicates) {
+ if (predicate.apply(f)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Collection<FilePredicate> predicates() {
+ return predicates;
+ }
+
+ @Override
+ public List<FilePredicate> operands() {
+ return predicates;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.nio.file.Paths;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.fs.PathPattern;
+
+/**
+ * @since 4.2
+ */
+class PathPatternPredicate extends AbstractFilePredicate {
+
+ private final PathPattern pattern;
+
+ PathPatternPredicate(PathPattern pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return pattern.match(f.path(), Paths.get(f.relativePath()));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.Collections;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.utils.PathUtils;
+
+/**
+ * @since 4.2
+ */
+public class RelativePathPredicate extends AbstractFilePredicate {
+
+ @Nullable
+ private final String path;
+
+ RelativePathPredicate(String path) {
+ this.path = PathUtils.sanitize(path);
+ }
+
+ public String path() {
+ return path;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ if (path == null) {
+ return false;
+ }
+
+ return path.equals(f.relativePath());
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ if (path != null) {
+ InputFile f = index.inputFile(this.path);
+ if (f != null) {
+ return Collections.singletonList(f);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int priority() {
+ return USE_INDEX;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @deprecated since 7.8
+ */
+@Deprecated
+public class StatusPredicate extends AbstractFilePredicate {
+
+ private final InputFile.Status status;
+
+ StatusPredicate(@Nullable InputFile.Status status) {
+ this.status = status;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return status == null || status == f.status();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+
+class TruePredicate extends AbstractFilePredicate {
+
+ static final FilePredicate TRUE = new TruePredicate();
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return true;
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ return index.inputFiles();
+ }
+
+ @Override
+ public Iterable<InputFile> filter(Iterable<InputFile> target) {
+ return target;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.sonar.api.batch.fs.InputFile;
+
+/**
+ * @since 4.2
+ */
+class TypePredicate extends AbstractFilePredicate {
+
+ private final InputFile.Type type;
+
+ TypePredicate(InputFile.Type type) {
+ this.type = type;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return type == f.type();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+import org.sonar.api.batch.fs.FileSystem.Index;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.scan.filesystem.PathResolver;
+
+/**
+ * @since 6.6
+ */
+class URIPredicate extends AbstractFilePredicate {
+
+ private final URI uri;
+ private final Path baseDir;
+
+ URIPredicate(URI uri, Path baseDir) {
+ this.baseDir = baseDir;
+ this.uri = uri;
+ }
+
+ @Override
+ public boolean apply(InputFile f) {
+ return uri.equals(f.uri());
+ }
+
+ @Override
+ public Iterable<InputFile> get(Index index) {
+ Path path = Paths.get(uri);
+ Optional<String> relative = PathResolver.relativize(baseDir, path);
+ if (!relative.isPresent()) {
+ return Collections.emptyList();
+ }
+ InputFile f = index.inputFile(relative.get());
+ return f != null ? Arrays.asList(f) : Collections.<InputFile>emptyList();
+ }
+
+ @Override
+ public int priority() {
+ return USE_INDEX;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.fs.predicates;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.issue;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.Issue.Flow;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.impl.fs.DefaultInputDir;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.sensor.DefaultStorable;
+import org.sonar.api.utils.PathUtils;
+
+import static java.util.Collections.unmodifiableList;
+import static java.util.stream.Collectors.toList;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable {
+ protected IssueLocation primaryLocation;
+ protected List<List<IssueLocation>> flows = new ArrayList<>();
+ protected DefaultInputProject project;
+
+ protected AbstractDefaultIssue(DefaultInputProject project) {
+ this(project, null);
+ }
+
+ public AbstractDefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
+ super(storage);
+ this.project = project;
+ }
+
+ public IssueLocation primaryLocation() {
+ return primaryLocation;
+ }
+
+ public List<Flow> flows() {
+ return this.flows.stream()
+ .<Flow>map(l -> () -> unmodifiableList(new ArrayList<>(l)))
+ .collect(toList());
+ }
+
+ public NewIssueLocation newLocation() {
+ return new DefaultIssueLocation();
+ }
+
+ public T at(NewIssueLocation primaryLocation) {
+ checkArgument(primaryLocation != null, "Cannot use a location that is null");
+ checkState(this.primaryLocation == null, "at() already called");
+ this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation);
+ checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component");
+ return (T) this;
+ }
+
+ public T addLocation(NewIssueLocation secondaryLocation) {
+ flows.add(Collections.singletonList(rewriteLocation((DefaultIssueLocation) secondaryLocation)));
+ return (T) this;
+ }
+
+ public T addFlow(Iterable<NewIssueLocation> locations) {
+ List<IssueLocation> flowAsList = new ArrayList<>();
+ for (NewIssueLocation issueLocation : locations) {
+ flowAsList.add(rewriteLocation((DefaultIssueLocation) issueLocation));
+ }
+ flows.add(flowAsList);
+ return (T) this;
+ }
+
+ private DefaultIssueLocation rewriteLocation(DefaultIssueLocation location) {
+ InputComponent component = location.inputComponent();
+ Optional<Path> dirOrModulePath = Optional.empty();
+
+ if (component instanceof DefaultInputDir) {
+ DefaultInputDir dirComponent = (DefaultInputDir) component;
+ dirOrModulePath = Optional.of(project.getBaseDir().relativize(dirComponent.path()));
+ } else if (component instanceof DefaultInputModule && !Objects.equals(project.key(), component.key())) {
+ DefaultInputModule moduleComponent = (DefaultInputModule) component;
+ dirOrModulePath = Optional.of(project.getBaseDir().relativize(moduleComponent.getBaseDir()));
+ }
+
+ if (dirOrModulePath.isPresent()) {
+ String path = PathUtils.sanitize(dirOrModulePath.get().toString());
+ DefaultIssueLocation fixedLocation = new DefaultIssueLocation();
+ fixedLocation.on(project);
+ StringBuilder fullMessage = new StringBuilder();
+ if (path != null && !path.isEmpty()) {
+ fullMessage.append("[").append(path).append("] ");
+ }
+ fullMessage.append(location.message());
+ fixedLocation.message(fullMessage.toString());
+ return fixedLocation;
+ } else {
+ return location;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.issue;
+
+import javax.annotation.Nullable;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.rule.RuleKey;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue {
+ private RuleKey ruleKey;
+ private Double gap;
+ private Severity overriddenSeverity;
+
+ public DefaultIssue(DefaultInputProject project) {
+ this(project, null);
+ }
+
+ public DefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
+ super(project, storage);
+ }
+
+ public DefaultIssue forRule(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ public RuleKey ruleKey() {
+ return this.ruleKey;
+ }
+
+ @Override
+ public DefaultIssue gap(@Nullable Double gap) {
+ checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
+ this.gap = gap;
+ return this;
+ }
+
+ @Override
+ public DefaultIssue overrideSeverity(@Nullable Severity severity) {
+ this.overriddenSeverity = severity;
+ return this;
+ }
+
+ @Override
+ public Severity overriddenSeverity() {
+ return this.overriddenSeverity;
+ }
+
+ @Override
+ public Double gap() {
+ return this.gap;
+ }
+
+ @Override
+ public IssueLocation primaryLocation() {
+ return primaryLocation;
+ }
+
+ @Override
+ public void doSave() {
+ requireNonNull(this.ruleKey, "ruleKey is mandatory on issue");
+ checkState(primaryLocation != null, "Primary location is mandatory on every issue");
+ storage.store(this);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.issue;
+
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.impl.fs.DefaultInputFile;
+
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang.StringUtils.abbreviate;
+import static org.apache.commons.lang.StringUtils.trim;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
+
+ private InputComponent component;
+ private TextRange textRange;
+ private String message;
+
+ @Override
+ public DefaultIssueLocation on(InputComponent component) {
+ checkArgument(component != null, "Component can't be null");
+ checkState(this.component == null, "on() already called");
+ this.component = component;
+ return this;
+ }
+
+ @Override
+ public DefaultIssueLocation at(TextRange location) {
+ checkState(this.component != null, "at() should be called after on()");
+ checkState(this.component.isFile(), "at() should be called only for an InputFile.");
+ DefaultInputFile file = (DefaultInputFile) this.component;
+ file.validate(location);
+ this.textRange = location;
+ return this;
+ }
+
+ @Override
+ public DefaultIssueLocation message(String message) {
+ requireNonNull(message, "Message can't be null");
+ if (message.contains("\u0000")) {
+ throw new IllegalArgumentException(unsupportedCharacterError(message, component));
+ }
+ this.message = abbreviate(trim(message), MESSAGE_MAX_SIZE);
+ return this;
+ }
+
+ private static String unsupportedCharacterError(String message, @Nullable InputComponent component) {
+ String error = "Character \\u0000 is not supported in issue message '" + message + "'";
+ if (component != null) {
+ error += ", on component: " + component.toString();
+ }
+ return error;
+ }
+
+ @Override
+ public InputComponent inputComponent() {
+ return this.component;
+ }
+
+ @Override
+ public TextRange textRange() {
+ return textRange;
+ }
+
+ @Override
+ public String message() {
+ return this.message;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.issue;
+
+import java.util.Set;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.issue.NoSonarFilter;
+import org.sonar.api.impl.fs.DefaultInputFile;
+
+public class DefaultNoSonarFilter extends NoSonarFilter {
+ public NoSonarFilter noSonarInFile(InputFile inputFile, Set<Integer> noSonarLines) {
+ ((DefaultInputFile) inputFile).noSonarAt(noSonarLines);
+ return this;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.issue;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.NewActiveRule;
+import org.sonar.api.rule.RuleKey;
+
+/**
+ * Builds instances of {@link org.sonar.api.batch.rule.ActiveRules}.
+ * <b>For unit testing and internal use only</b>.
+ *
+ * @since 4.2
+ */
+public class ActiveRulesBuilder {
+
+ private final Map<RuleKey, NewActiveRule> map = new LinkedHashMap<>();
+
+ public ActiveRulesBuilder addRule(NewActiveRule newActiveRule) {
+ if (map.containsKey(newActiveRule.ruleKey())) {
+ throw new IllegalStateException(String.format("Rule '%s' is already activated", newActiveRule.ruleKey()));
+ }
+ map.put(newActiveRule.ruleKey(), newActiveRule);
+ return this;
+ }
+
+ public ActiveRules build() {
+ return new DefaultActiveRules(map.values());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.rule.ActiveRule;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.DefaultActiveRule;
+import org.sonar.api.batch.rule.NewActiveRule;
+import org.sonar.api.rule.RuleKey;
+
+@Immutable
+public class DefaultActiveRules implements ActiveRules {
+ private final Map<String, List<ActiveRule>> activeRulesByRepository = new HashMap<>();
+ private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndKey = new HashMap<>();
+ private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndInternalKey = new HashMap<>();
+ private final Map<String, List<ActiveRule>> activeRulesByLanguage = new HashMap<>();
+
+ public DefaultActiveRules(Collection<NewActiveRule> newActiveRules) {
+ for (NewActiveRule newAR : newActiveRules) {
+ DefaultActiveRule ar = new DefaultActiveRule(newAR);
+ String repo = ar.ruleKey().repository();
+ activeRulesByRepository.computeIfAbsent(repo, x -> new ArrayList<>()).add(ar);
+ if (ar.language() != null) {
+ activeRulesByLanguage.computeIfAbsent(ar.language(), x -> new ArrayList<>()).add(ar);
+ }
+
+ activeRulesByRepositoryAndKey.computeIfAbsent(repo, r -> new HashMap<>()).put(ar.ruleKey().rule(), ar);
+ String internalKey = ar.internalKey();
+ if (internalKey != null) {
+ activeRulesByRepositoryAndInternalKey.computeIfAbsent(repo, r -> new HashMap<>()).put(internalKey, ar);
+ }
+ }
+ }
+
+ @Override
+ public ActiveRule find(RuleKey ruleKey) {
+ return activeRulesByRepositoryAndKey.getOrDefault(ruleKey.repository(), Collections.emptyMap())
+ .get(ruleKey.rule());
+ }
+
+ @Override
+ public Collection<ActiveRule> findAll() {
+ return activeRulesByRepository.entrySet().stream().flatMap(x -> x.getValue().stream()).collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection<ActiveRule> findByRepository(String repository) {
+ return activeRulesByRepository.getOrDefault(repository, Collections.emptyList());
+ }
+
+ @Override
+ public Collection<ActiveRule> findByLanguage(String language) {
+ return activeRulesByLanguage.getOrDefault(language, Collections.emptyList());
+ }
+
+ @Override
+ public ActiveRule findByInternalKey(String repository, String internalKey) {
+ return activeRulesByRepositoryAndInternalKey.containsKey(repository) ? activeRulesByRepositoryAndInternalKey.get(repository).get(internalKey) : null;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.batch.rule.DefaultRule;
+import org.sonar.api.batch.rule.NewRule;
+import org.sonar.api.batch.rule.Rule;
+import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.rule.RuleKey;
+
+@Immutable
+class DefaultRules implements Rules {
+ private final Map<String, List<Rule>> rulesByRepository;
+ private final Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKey;
+ private final Map<RuleKey, Rule> rulesByRuleKey;
+
+ DefaultRules(Collection<NewRule> newRules) {
+ Map<String, List<Rule>> rulesByRepositoryBuilder = new HashMap<>();
+ Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder = new HashMap<>();
+ Map<RuleKey, Rule> rulesByRuleKeyBuilder = new HashMap<>();
+
+ for (NewRule newRule : newRules) {
+ DefaultRule r = new DefaultRule(newRule);
+ rulesByRuleKeyBuilder.put(r.key(), r);
+ rulesByRepositoryBuilder.computeIfAbsent(r.key().repository(), x -> new ArrayList<>()).add(r);
+ addToTable(rulesByRepositoryAndInternalKeyBuilder, r);
+ }
+
+ rulesByRuleKey = Collections.unmodifiableMap(rulesByRuleKeyBuilder);
+ rulesByRepository = Collections.unmodifiableMap(rulesByRepositoryBuilder);
+ rulesByRepositoryAndInternalKey = Collections.unmodifiableMap(rulesByRepositoryAndInternalKeyBuilder);
+ }
+
+ private static void addToTable(Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder, DefaultRule r) {
+ if (r.internalKey() == null) {
+ return;
+ }
+
+ rulesByRepositoryAndInternalKeyBuilder
+ .computeIfAbsent(r.key().repository(), x -> new HashMap<>())
+ .computeIfAbsent(r.internalKey(), x -> new ArrayList<>())
+ .add(r);
+ }
+
+ @Override
+ public Rule find(RuleKey ruleKey) {
+ return rulesByRuleKey.get(ruleKey);
+ }
+
+ @Override
+ public Collection<Rule> findAll() {
+ return rulesByRepository.values().stream().flatMap(List::stream).collect(Collectors.toList());
+ }
+
+ @Override
+ public Collection<Rule> findByRepository(String repository) {
+ return rulesByRepository.getOrDefault(repository, Collections.emptyList());
+ }
+
+ @Override
+ public Collection<Rule> findByInternalKey(String repository, String internalKey) {
+ return rulesByRepositoryAndInternalKey
+ .getOrDefault(repository, Collections.emptyMap())
+ .getOrDefault(internalKey, Collections.emptyList());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.sonar.api.batch.rule.NewRule;
+import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.rule.RuleKey;
+
+/**
+ * For unit testing and internal use only.
+ *
+ * @since 4.2
+ */
+
+public class RulesBuilder {
+
+ private final Map<RuleKey, NewRule> map = new HashMap<>();
+
+ public NewRule add(RuleKey key) {
+ if (map.containsKey(key)) {
+ throw new IllegalStateException(String.format("Rule '%s' already exists", key));
+ }
+ NewRule newRule = new NewRule(key);
+ map.put(key, newRule);
+ return newRule;
+ }
+
+ public Rules build() {
+ return new DefaultRules(map.values());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.rules.RuleType;
+
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultAdHocRule extends DefaultStorable implements AdHocRule, NewAdHocRule {
+ private Severity severity;
+ private RuleType type;
+ private String name;
+ private String description;
+ private String engineId;
+ private String ruleId;
+
+ public DefaultAdHocRule() {
+ super(null);
+ }
+
+ public DefaultAdHocRule(@Nullable SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultAdHocRule severity(Severity severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ @Override
+ public String engineId() {
+ return engineId;
+ }
+
+ @Override
+ public String ruleId() {
+ return ruleId;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @CheckForNull
+ @Override
+ public String description() {
+ return description;
+ }
+
+ @Override
+ public Severity severity() {
+ return this.severity;
+ }
+
+ @Override
+ public void doSave() {
+ checkState(isNotBlank(engineId), "Engine id is mandatory on ad hoc rule");
+ checkState(isNotBlank(ruleId), "Rule id is mandatory on ad hoc rule");
+ checkState(isNotBlank(name), "Name is mandatory on every ad hoc rule");
+ checkState(severity != null, "Severity is mandatory on every ad hoc rule");
+ checkState(type != null, "Type is mandatory on every ad hoc rule");
+ storage.store(this);
+ }
+
+ @Override
+ public RuleType type() {
+ return type;
+ }
+
+ @Override
+ public DefaultAdHocRule engineId(String engineId) {
+ this.engineId = engineId;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule ruleId(String ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule description(@Nullable String description) {
+ this.description = description;
+ return this;
+ }
+
+ @Override
+ public DefaultAdHocRule type(RuleType type) {
+ this.type = type;
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextPointer;
+import org.sonar.api.batch.sensor.error.AnalysisError;
+import org.sonar.api.batch.sensor.error.NewAnalysisError;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultAnalysisError extends DefaultStorable implements NewAnalysisError, AnalysisError {
+ private InputFile inputFile;
+ private String message;
+ private TextPointer location;
+
+ public DefaultAnalysisError() {
+ super(null);
+ }
+
+ public DefaultAnalysisError(SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public String message() {
+ return message;
+ }
+
+ @Override
+ public TextPointer location() {
+ return location;
+ }
+
+ @Override
+ public NewAnalysisError onFile(InputFile inputFile) {
+ checkArgument(inputFile != null, "Cannot use a inputFile that is null");
+ checkState(this.inputFile == null, "onFile() already called");
+ this.inputFile = inputFile;
+ return this;
+ }
+
+ @Override
+ public NewAnalysisError message(String message) {
+ this.message = message;
+ return this;
+ }
+
+ @Override
+ public NewAnalysisError at(TextPointer location) {
+ checkState(this.location == null, "at() already called");
+ this.location = location;
+ return this;
+ }
+
+ @Override
+ protected void doSave() {
+ requireNonNull(this.inputFile, "inputFile is mandatory on AnalysisError");
+ storage.store(this);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Collections;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.coverage.CoverageType;
+import org.sonar.api.batch.sensor.coverage.NewCoverage;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultInputFile;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultCoverage extends DefaultStorable implements NewCoverage {
+
+ private InputFile inputFile;
+ private CoverageType type;
+ private int totalCoveredLines = 0;
+ private int totalConditions = 0;
+ private int totalCoveredConditions = 0;
+ private SortedMap<Integer, Integer> hitsByLine = new TreeMap<>();
+ private SortedMap<Integer, Integer> conditionsByLine = new TreeMap<>();
+ private SortedMap<Integer, Integer> coveredConditionsByLine = new TreeMap<>();
+
+ public DefaultCoverage() {
+ super();
+ }
+
+ public DefaultCoverage(@Nullable SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultCoverage onFile(InputFile inputFile) {
+ this.inputFile = inputFile;
+ return this;
+ }
+
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public NewCoverage ofType(CoverageType type) {
+ this.type = requireNonNull(type, "type can't be null");
+ return this;
+ }
+
+ public CoverageType type() {
+ return type;
+ }
+
+ @Override
+ public NewCoverage lineHits(int line, int hits) {
+ validateFile();
+ if (isExcluded()) {
+ return this;
+ }
+ validateLine(line);
+
+ if (!hitsByLine.containsKey(line)) {
+ hitsByLine.put(line, hits);
+ if (hits > 0) {
+ totalCoveredLines += 1;
+ }
+ }
+ return this;
+ }
+
+ private void validateLine(int line) {
+ checkState(line <= inputFile.lines(), "Line %s is out of range in the file %s (lines: %s)", line, inputFile, inputFile.lines());
+ checkState(line > 0, "Line number must be strictly positive: %s", line);
+ }
+
+ private void validateFile() {
+ requireNonNull(inputFile, "Call onFile() first");
+ }
+
+ @Override
+ public NewCoverage conditions(int line, int conditions, int coveredConditions) {
+ validateFile();
+ if (isExcluded()) {
+ return this;
+ }
+ validateLine(line);
+
+ if (conditions > 0 && !conditionsByLine.containsKey(line)) {
+ totalConditions += conditions;
+ totalCoveredConditions += coveredConditions;
+ conditionsByLine.put(line, conditions);
+ coveredConditionsByLine.put(line, coveredConditions);
+ }
+ return this;
+ }
+
+ public int coveredLines() {
+ return totalCoveredLines;
+ }
+
+ public int linesToCover() {
+ return hitsByLine.size();
+ }
+
+ public int conditions() {
+ return totalConditions;
+ }
+
+ public int coveredConditions() {
+ return totalCoveredConditions;
+ }
+
+ public SortedMap<Integer, Integer> hitsByLine() {
+ return Collections.unmodifiableSortedMap(hitsByLine);
+ }
+
+ public SortedMap<Integer, Integer> conditionsByLine() {
+ return Collections.unmodifiableSortedMap(conditionsByLine);
+ }
+
+ public SortedMap<Integer, Integer> coveredConditionsByLine() {
+ return Collections.unmodifiableSortedMap(coveredConditionsByLine);
+ }
+
+ @Override
+ public void doSave() {
+ validateFile();
+ if (!isExcluded()) {
+ storage.store(this);
+ }
+ }
+
+ private boolean isExcluded() {
+ return ((DefaultInputFile) inputFile).isExcludedForCoverage();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+import static java.util.Collections.unmodifiableList;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
+ private static final Logger LOG = Loggers.get(DefaultCpdTokens.class);
+ private final List<TokensLine> result = new ArrayList<>();
+ private DefaultInputFile inputFile;
+ private int startLine = Integer.MIN_VALUE;
+ private int startIndex = 0;
+ private int currentIndex = 0;
+ private StringBuilder sb = new StringBuilder();
+ private TextRange lastRange;
+ private boolean loggedTestCpdWarning = false;
+
+ public DefaultCpdTokens(SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultCpdTokens onFile(InputFile inputFile) {
+ this.inputFile = (DefaultInputFile) requireNonNull(inputFile, "file can't be null");
+ return this;
+ }
+
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public NewCpdTokens addToken(int startLine, int startLineOffset, int endLine, int endLineOffset, String image) {
+ checkInputFileNotNull();
+ TextRange newRange;
+ try {
+ newRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to register token in file " + inputFile, e);
+ }
+ return addToken(newRange, image);
+ }
+
+ @Override
+ public DefaultCpdTokens addToken(TextRange range, String image) {
+ requireNonNull(range, "Range should not be null");
+ requireNonNull(image, "Image should not be null");
+ checkInputFileNotNull();
+ if (isExcludedForDuplication()) {
+ return this;
+ }
+ checkState(lastRange == null || lastRange.end().compareTo(range.start()) <= 0,
+ "Tokens of file %s should be provided in order.\nPrevious token: %s\nLast token: %s", inputFile, lastRange, range);
+
+ int line = range.start().line();
+ if (line != startLine) {
+ addNewTokensLine(result, startIndex, currentIndex, startLine, sb);
+ startIndex = currentIndex + 1;
+ startLine = line;
+ }
+ currentIndex++;
+ sb.append(image);
+ lastRange = range;
+
+ return this;
+ }
+
+ private boolean isExcludedForDuplication() {
+ if (inputFile.isExcludedForDuplication()) {
+ return true;
+ }
+ if (inputFile.type() == InputFile.Type.TEST) {
+ if (!loggedTestCpdWarning) {
+ LOG.warn("Duplication reported for '{}' will be ignored because it's a test file.", inputFile);
+ loggedTestCpdWarning = true;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public List<TokensLine> getTokenLines() {
+ return unmodifiableList(new ArrayList<>(result));
+ }
+
+ private static void addNewTokensLine(List<TokensLine> result, int startUnit, int endUnit, int startLine, StringBuilder sb) {
+ if (sb.length() != 0) {
+ result.add(new TokensLine(startUnit, endUnit, startLine, sb.toString()));
+ sb.setLength(0);
+ }
+ }
+
+ @Override
+ protected void doSave() {
+ checkState(inputFile != null, "Call onFile() first");
+ if (isExcludedForDuplication()) {
+ return;
+ }
+ addNewTokensLine(result, startIndex, currentIndex, startLine, sb);
+ storage.store(this);
+ }
+
+ private void checkInputFileNotNull() {
+ checkState(inputFile != null, "Call onFile() first");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import javax.annotation.Nullable;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.ExternalIssue;
+import org.sonar.api.batch.sensor.issue.NewExternalIssue;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.issue.AbstractDefaultIssue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.RuleType;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIssue> implements ExternalIssue, NewExternalIssue {
+ private Long effort;
+ private Severity severity;
+ private RuleType type;
+ private String engineId;
+ private String ruleId;
+
+ public DefaultExternalIssue(DefaultInputProject project) {
+ this(project, null);
+ }
+
+ public DefaultExternalIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
+ super(project, storage);
+ }
+
+ @Override
+ public DefaultExternalIssue remediationEffortMinutes(@Nullable Long effort) {
+ checkArgument(effort == null || effort >= 0, format("effort must be greater than or equal 0 (got %s)", effort));
+ this.effort = effort;
+ return this;
+ }
+
+ @Override
+ public DefaultExternalIssue severity(Severity severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ @Override
+ public String engineId() {
+ return engineId;
+ }
+
+ @Override
+ public String ruleId() {
+ return ruleId;
+ }
+
+ @Override
+ public Severity severity() {
+ return this.severity;
+ }
+
+ @Override
+ public Long remediationEffort() {
+ return this.effort;
+ }
+
+ @Override
+ public void doSave() {
+ requireNonNull(this.engineId, "Engine id is mandatory on external issue");
+ requireNonNull(this.ruleId, "Rule id is mandatory on external issue");
+ checkState(primaryLocation != null, "Primary location is mandatory on every external issue");
+ checkState(primaryLocation.inputComponent().isFile(), "External issues must be located in files");
+ checkState(primaryLocation.message() != null, "External issues must have a message");
+ checkState(severity != null, "Severity is mandatory on every external issue");
+ checkState(type != null, "Type is mandatory on every external issue");
+ storage.store(this);
+ }
+
+ @Override
+ public RuleType type() {
+ return type;
+ }
+
+ @Override
+ public NewExternalIssue engineId(String engineId) {
+ this.engineId = engineId;
+ return this;
+ }
+
+ @Override
+ public NewExternalIssue ruleId(String ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ @Override
+ public DefaultExternalIssue forRule(RuleKey ruleKey) {
+ this.engineId = ruleKey.repository();
+ this.ruleId = ruleKey.rule();
+ return this;
+ }
+
+ @Override
+ public RuleKey ruleKey() {
+ if (engineId != null && ruleId != null) {
+ return RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, ruleId);
+ }
+ return null;
+ }
+
+ @Override
+ public DefaultExternalIssue type(RuleType type) {
+ this.type = type;
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
+import org.sonar.api.batch.sensor.highlighting.TypeOfText;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultInputFile;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultHighlighting extends DefaultStorable implements NewHighlighting {
+
+ private final List<SyntaxHighlightingRule> syntaxHighlightingRules;
+ private DefaultInputFile inputFile;
+
+ public DefaultHighlighting(SensorStorage storage) {
+ super(storage);
+ syntaxHighlightingRules = new ArrayList<>();
+ }
+
+ public List<SyntaxHighlightingRule> getSyntaxHighlightingRuleSet() {
+ return syntaxHighlightingRules;
+ }
+
+ private void checkOverlappingBoundaries() {
+ if (syntaxHighlightingRules.size() > 1) {
+ Iterator<SyntaxHighlightingRule> it = syntaxHighlightingRules.iterator();
+ SyntaxHighlightingRule previous = it.next();
+ while (it.hasNext()) {
+ SyntaxHighlightingRule current = it.next();
+ if (previous.range().end().compareTo(current.range().start()) > 0 && (previous.range().end().compareTo(current.range().end()) < 0)) {
+ String errorMsg = String.format("Cannot register highlighting rule for characters at %s as it " +
+ "overlaps at least one existing rule", current.range());
+ throw new IllegalStateException(errorMsg);
+ }
+ previous = current;
+ }
+ }
+ }
+
+ @Override
+ public DefaultHighlighting onFile(InputFile inputFile) {
+ requireNonNull(inputFile, "file can't be null");
+ this.inputFile = (DefaultInputFile) inputFile;
+ return this;
+ }
+
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public DefaultHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText) {
+ checkInputFileNotNull();
+ TextRange newRange;
+ try {
+ newRange = inputFile.newRange(startOffset, endOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to highlight file " + inputFile, e);
+ }
+ return highlight(newRange, typeOfText);
+ }
+
+ @Override
+ public DefaultHighlighting highlight(int startLine, int startLineOffset, int endLine, int endLineOffset, TypeOfText typeOfText) {
+ checkInputFileNotNull();
+ TextRange newRange;
+ try {
+ newRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to highlight file " + inputFile, e);
+ }
+ return highlight(newRange, typeOfText);
+ }
+
+ @Override
+ public DefaultHighlighting highlight(TextRange range, TypeOfText typeOfText) {
+ SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(range, typeOfText);
+ this.syntaxHighlightingRules.add(syntaxHighlightingRule);
+ return this;
+ }
+
+ @Override
+ protected void doSave() {
+ checkInputFileNotNull();
+ // Sort rules to avoid variation during consecutive runs
+ Collections.sort(syntaxHighlightingRules, (left, right) -> {
+ int result = left.range().start().compareTo(right.range().start());
+ if (result == 0) {
+ result = right.range().end().compareTo(left.range().end());
+ }
+ return result;
+ });
+ checkOverlappingBoundaries();
+ storage.store(this);
+ }
+
+ private void checkInputFileNotNull() {
+ checkState(inputFile != null, "Call onFile() first");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.Serializable;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.measure.NewMeasure;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G>, NewMeasure<G> {
+
+ private InputComponent component;
+ private Metric<G> metric;
+ private G value;
+ private boolean fromCore = false;
+
+ public DefaultMeasure() {
+ super();
+ }
+
+ public DefaultMeasure(@Nullable SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultMeasure<G> on(InputComponent component) {
+ checkArgument(component != null, "Component can't be null");
+ checkState(this.component == null, "on() already called");
+ this.component = component;
+ return this;
+ }
+
+ @Override
+ public DefaultMeasure<G> forMetric(Metric<G> metric) {
+ checkState(this.metric == null, "Metric already defined");
+ requireNonNull(metric, "metric should be non null");
+ this.metric = metric;
+ return this;
+ }
+
+ @Override
+ public DefaultMeasure<G> withValue(G value) {
+ checkState(this.value == null, "Measure value already defined");
+ requireNonNull(value, "Measure value can't be null");
+ this.value = value;
+ return this;
+ }
+
+ /**
+ * For internal use.
+ */
+ public boolean isFromCore() {
+ return fromCore;
+ }
+
+ /**
+ * For internal use. Used by core components to bypass check that prevent a plugin to store core measures.
+ */
+ public DefaultMeasure<G> setFromCore() {
+ this.fromCore = true;
+ return this;
+ }
+
+ @Override
+ public void doSave() {
+ requireNonNull(this.value, "Measure value can't be null");
+ requireNonNull(this.metric, "Measure metric can't be null");
+ checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type %s", this.metric.valueType());
+ storage.store(this);
+ }
+
+ @Override
+ public Metric<G> metric() {
+ return metric;
+ }
+
+ @Override
+ public InputComponent inputComponent() {
+ return component;
+ }
+
+ @Override
+ public G value() {
+ return value;
+ }
+
+ // 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;
+ }
+ DefaultMeasure<?> rhs = (DefaultMeasure<?>) obj;
+ return new EqualsBuilder()
+ .append(component, rhs.component)
+ .append(metric, rhs.metric)
+ .append(value, rhs.value)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(27, 45).append(component).append(metric).append(value).toHashCode();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.sonar.api.batch.postjob.PostJobDescriptor;
+
+public class DefaultPostJobDescriptor implements PostJobDescriptor {
+
+ private String name;
+ private String[] properties = new String[0];
+
+ public String name() {
+ return name;
+ }
+
+ public Collection<String> properties() {
+ return Arrays.asList(properties);
+ }
+
+ @Override
+ public DefaultPostJobDescriptor name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public DefaultPostJobDescriptor requireProperty(String... propertyKey) {
+ return requireProperties(propertyKey);
+ }
+
+ @Override
+ public DefaultPostJobDescriptor requireProperties(String... propertyKeys) {
+ this.properties = propertyKeys;
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.Predicate;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.config.Configuration;
+
+import static java.util.Arrays.asList;
+
+public class DefaultSensorDescriptor implements SensorDescriptor {
+
+ private String name;
+ private String[] languages = new String[0];
+ private InputFile.Type type = null;
+ private String[] ruleRepositories = new String[0];
+ private boolean global = false;
+ private Predicate<Configuration> configurationPredicate;
+
+ public String name() {
+ return name;
+ }
+
+ public Collection<String> languages() {
+ return Arrays.asList(languages);
+ }
+
+ @Nullable
+ public InputFile.Type type() {
+ return type;
+ }
+
+ public Collection<String> ruleRepositories() {
+ return Arrays.asList(ruleRepositories);
+ }
+
+ public Predicate<Configuration> configurationPredicate() {
+ return configurationPredicate;
+ }
+
+ public boolean isGlobal() {
+ return global;
+ }
+
+ @Override
+ public DefaultSensorDescriptor name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ public DefaultSensorDescriptor onlyOnLanguage(String languageKey) {
+ return onlyOnLanguages(languageKey);
+ }
+
+ @Override
+ public DefaultSensorDescriptor onlyOnLanguages(String... languageKeys) {
+ this.languages = languageKeys;
+ return this;
+ }
+
+ @Override
+ public DefaultSensorDescriptor onlyOnFileType(InputFile.Type type) {
+ this.type = type;
+ return this;
+ }
+
+ @Override
+ public DefaultSensorDescriptor createIssuesForRuleRepository(String... repositoryKey) {
+ return createIssuesForRuleRepositories(repositoryKey);
+ }
+
+ @Override
+ public DefaultSensorDescriptor createIssuesForRuleRepositories(String... repositoryKeys) {
+ this.ruleRepositories = repositoryKeys;
+ return this;
+ }
+
+ @Override
+ public DefaultSensorDescriptor requireProperty(String... propertyKey) {
+ return requireProperties(propertyKey);
+ }
+
+ @Override
+ public DefaultSensorDescriptor requireProperties(String... propertyKeys) {
+ this.configurationPredicate = config -> asList(propertyKeys).stream().allMatch(config::hasKey);
+ return this;
+ }
+
+ @Override
+ public SensorDescriptor global() {
+ this.global = true;
+ return this;
+ }
+
+ @Override
+ public SensorDescriptor onlyWhenConfiguration(Predicate<Configuration> configurationPredicate) {
+ this.configurationPredicate = configurationPredicate;
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.annotation.Nullable;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.code.NewSignificantCode;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.utils.Preconditions;
+
+public class DefaultSignificantCode extends DefaultStorable implements NewSignificantCode {
+ private SortedMap<Integer, TextRange> significantCodePerLine = new TreeMap<>();
+ private InputFile inputFile;
+
+ public DefaultSignificantCode() {
+ super();
+ }
+
+ public DefaultSignificantCode(@Nullable SensorStorage storage) {
+ super(storage);
+ }
+
+ @Override
+ public DefaultSignificantCode onFile(InputFile inputFile) {
+ this.inputFile = inputFile;
+ return this;
+ }
+
+ @Override
+ public DefaultSignificantCode addRange(TextRange range) {
+ Preconditions.checkState(this.inputFile != null, "addRange() should be called after on()");
+
+ int line = range.start().line();
+
+ Preconditions.checkArgument(line == range.end().line(), "Ranges of significant code must be located in a single line");
+ Preconditions.checkState(!significantCodePerLine.containsKey(line), "Significant code was already reported for line '%s'. Can only report once per line.", line);
+
+ significantCodePerLine.put(line, range);
+ return this;
+ }
+
+ @Override
+ protected void doSave() {
+ Preconditions.checkState(inputFile != null, "Call onFile() first");
+ storage.store(this);
+ }
+
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ public SortedMap<Integer, TextRange> significantCodePerLine() {
+ return significantCodePerLine;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public abstract class DefaultStorable {
+
+ protected final transient SensorStorage storage;
+ private transient boolean saved = false;
+
+ public DefaultStorable() {
+ this.storage = null;
+ }
+
+ public DefaultStorable(@Nullable SensorStorage storage) {
+ this.storage = storage;
+ }
+
+ public final void save() {
+ requireNonNull(this.storage, "No persister on this object");
+ checkState(!saved, "This object was already saved");
+ doSave();
+ this.saved = true;
+ }
+
+ protected abstract void doSave();
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.symbol.NewSymbol;
+import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
+import org.sonar.api.impl.fs.DefaultInputFile;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTable {
+
+ private final Map<TextRange, Set<TextRange>> referencesBySymbol;
+ private DefaultInputFile inputFile;
+
+ public DefaultSymbolTable(SensorStorage storage) {
+ super(storage);
+ referencesBySymbol = new LinkedHashMap<>();
+ }
+
+ public Map<TextRange, Set<TextRange>> getReferencesBySymbol() {
+ return referencesBySymbol;
+ }
+
+ @Override
+ public DefaultSymbolTable onFile(InputFile inputFile) {
+ requireNonNull(inputFile, "file can't be null");
+ this.inputFile = (DefaultInputFile) inputFile;
+ return this;
+ }
+
+ public InputFile inputFile() {
+ return inputFile;
+ }
+
+ @Override
+ public NewSymbol newSymbol(int startLine, int startLineOffset, int endLine, int endLineOffset) {
+ checkInputFileNotNull();
+ TextRange declarationRange;
+ try {
+ declarationRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to create symbol on file " + inputFile, e);
+ }
+ return newSymbol(declarationRange);
+ }
+
+ @Override
+ public NewSymbol newSymbol(int startOffset, int endOffset) {
+ checkInputFileNotNull();
+ TextRange declarationRange;
+ try {
+ declarationRange = inputFile.newRange(startOffset, endOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to create symbol on file " + inputFile, e);
+ }
+ return newSymbol(declarationRange);
+ }
+
+ @Override
+ public NewSymbol newSymbol(TextRange range) {
+ checkInputFileNotNull();
+ TreeSet<TextRange> references = new TreeSet<>((o1, o2) -> o1.start().compareTo(o2.start()));
+ referencesBySymbol.put(range, references);
+ return new DefaultSymbol(inputFile, range, references);
+ }
+
+ private static class DefaultSymbol implements NewSymbol {
+
+ private final Collection<TextRange> references;
+ private final DefaultInputFile inputFile;
+ private final TextRange declaration;
+
+ public DefaultSymbol(DefaultInputFile inputFile, TextRange declaration, Collection<TextRange> references) {
+ this.inputFile = inputFile;
+ this.declaration = declaration;
+ this.references = references;
+ }
+
+ @Override
+ public NewSymbol newReference(int startOffset, int endOffset) {
+ TextRange referenceRange;
+ try {
+ referenceRange = inputFile.newRange(startOffset, endOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to create symbol reference on file " + inputFile, e);
+ }
+ return newReference(referenceRange);
+ }
+
+ @Override
+ public NewSymbol newReference(int startLine, int startLineOffset, int endLine, int endLineOffset) {
+ TextRange referenceRange;
+ try {
+ referenceRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Unable to create symbol reference on file " + inputFile, e);
+ }
+ return newReference(referenceRange);
+ }
+
+ @Override
+ public NewSymbol newReference(TextRange range) {
+ requireNonNull(range, "Provided range is null");
+ checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration);
+ references.add(range);
+ return this;
+ }
+
+ }
+
+ @Override
+ protected void doSave() {
+ checkInputFileNotNull();
+ storage.store(this);
+ }
+
+ private void checkInputFileNotNull() {
+ checkState(inputFile != null, "Call onFile() first");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.sonar.api.batch.sensor.code.NewSignificantCode;
+import org.sonar.api.batch.sensor.coverage.NewCoverage;
+import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
+import org.sonar.api.batch.sensor.error.AnalysisError;
+import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.issue.ExternalIssue;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+class InMemorySensorStorage implements SensorStorage {
+
+ Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>();
+
+ Collection<Issue> allIssues = new ArrayList<>();
+ Collection<ExternalIssue> allExternalIssues = new ArrayList<>();
+ Collection<AdHocRule> allAdHocRules = new ArrayList<>();
+ Collection<AnalysisError> allAnalysisErrors = new ArrayList<>();
+
+ Map<String, NewHighlighting> highlightingByComponent = new HashMap<>();
+ Map<String, DefaultCpdTokens> cpdTokensByComponent = new HashMap<>();
+ Map<String, List<DefaultCoverage>> coverageByComponent = new HashMap<>();
+ Map<String, DefaultSymbolTable> symbolsPerComponent = new HashMap<>();
+ Map<String, String> contextProperties = new HashMap<>();
+ Map<String, DefaultSignificantCode> significantCodePerComponent = new HashMap<>();
+
+ @Override
+ public void store(Measure measure) {
+ // Emulate duplicate measure check
+ String componentKey = measure.inputComponent().key();
+ String metricKey = measure.metric().key();
+ if (measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).containsKey(metricKey)) {
+ throw new IllegalStateException("Can not add the same measure twice");
+ }
+ measuresByComponentAndMetric.computeIfAbsent(componentKey, x -> new HashMap<>()).put(metricKey, measure);
+ }
+
+ @Override
+ public void store(Issue issue) {
+ allIssues.add(issue);
+ }
+
+ @Override
+ public void store(AdHocRule adHocRule) {
+ allAdHocRules.add(adHocRule);
+ }
+
+ @Override
+ public void store(NewHighlighting newHighlighting) {
+ DefaultHighlighting highlighting = (DefaultHighlighting) newHighlighting;
+ String fileKey = highlighting.inputFile().key();
+ // Emulate duplicate storage check
+ if (highlightingByComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save highlighting twice for the same file is not supported: " + highlighting.inputFile());
+ }
+ highlightingByComponent.put(fileKey, highlighting);
+ }
+
+ @Override
+ public void store(NewCoverage coverage) {
+ DefaultCoverage defaultCoverage = (DefaultCoverage) coverage;
+ String fileKey = defaultCoverage.inputFile().key();
+ coverageByComponent.computeIfAbsent(fileKey, x -> new ArrayList<>()).add(defaultCoverage);
+ }
+
+ @Override
+ public void store(NewCpdTokens cpdTokens) {
+ DefaultCpdTokens defaultCpdTokens = (DefaultCpdTokens) cpdTokens;
+ String fileKey = defaultCpdTokens.inputFile().key();
+ // Emulate duplicate storage check
+ if (cpdTokensByComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + defaultCpdTokens.inputFile());
+ }
+ cpdTokensByComponent.put(fileKey, defaultCpdTokens);
+ }
+
+ @Override
+ public void store(NewSymbolTable newSymbolTable) {
+ DefaultSymbolTable symbolTable = (DefaultSymbolTable) newSymbolTable;
+ String fileKey = symbolTable.inputFile().key();
+ // Emulate duplicate storage check
+ if (symbolsPerComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save symbol table twice for the same file is not supported: " + symbolTable.inputFile());
+ }
+ symbolsPerComponent.put(fileKey, symbolTable);
+ }
+
+ @Override
+ public void store(AnalysisError analysisError) {
+ allAnalysisErrors.add(analysisError);
+ }
+
+ @Override
+ public void storeProperty(String key, String value) {
+ checkArgument(key != null, "Key of context property must not be null");
+ checkArgument(value != null, "Value of context property must not be null");
+ contextProperties.put(key, value);
+ }
+
+ @Override
+ public void store(ExternalIssue issue) {
+ allExternalIssues.add(issue);
+ }
+
+ @Override
+ public void store(NewSignificantCode newSignificantCode) {
+ DefaultSignificantCode significantCode = (DefaultSignificantCode) newSignificantCode;
+ String fileKey = significantCode.inputFile().key();
+ // Emulate duplicate storage check
+ if (significantCodePerComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save significant code information twice for the same file is not supported: " + significantCode.inputFile());
+ }
+ significantCodePerComponent.put(fileKey, significantCode);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.File;
+import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.code.NewSignificantCode;
+import org.sonar.api.batch.sensor.coverage.NewCoverage;
+import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
+import org.sonar.api.batch.sensor.error.AnalysisError;
+import org.sonar.api.batch.sensor.error.NewAnalysisError;
+import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
+import org.sonar.api.batch.sensor.highlighting.TypeOfText;
+import org.sonar.api.batch.sensor.issue.ExternalIssue;
+import org.sonar.api.batch.sensor.issue.Issue;
+import org.sonar.api.batch.sensor.issue.NewExternalIssue;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.batch.sensor.measure.Measure;
+import org.sonar.api.batch.sensor.measure.NewMeasure;
+import org.sonar.api.batch.sensor.rule.AdHocRule;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.config.Settings;
+import org.sonar.api.impl.config.ConfigurationBridge;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.issue.DefaultIssue;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
+import org.sonar.api.impl.context.MetadataLoader;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
+import org.sonar.api.measures.Metric;
+import org.sonar.api.scanner.fs.InputProject;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.Version;
+
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * Utility class to help testing {@link Sensor}. This is not an API and method signature may evolve.
+ * <p>
+ * Usage: call {@link #create(File)} to create an "in memory" implementation of {@link SensorContext} with a filesystem initialized with provided baseDir.
+ * <p>
+ * You have to manually register inputFiles using:
+ * <pre>
+ * sensorContextTester.fileSystem().add(new DefaultInputFile("myProjectKey", "src/Foo.java")
+ * .setLanguage("java")
+ * .initMetadata("public class Foo {\n}"));
+ * </pre>
+ * <p>
+ * Then pass it to your {@link Sensor}. You can then query elements provided by your sensor using methods {@link #allIssues()}, ...
+ */
+public class SensorContextTester implements SensorContext {
+
+ private Settings settings;
+ private DefaultFileSystem fs;
+ private ActiveRules activeRules;
+ private InMemorySensorStorage sensorStorage;
+ private DefaultInputProject project;
+ private DefaultInputModule module;
+ private SonarRuntime runtime;
+ private boolean cancelled;
+
+ private SensorContextTester(Path moduleBaseDir) {
+ this.settings = new MapSettings();
+ this.fs = new DefaultFileSystem(moduleBaseDir).setEncoding(Charset.defaultCharset());
+ this.activeRules = new ActiveRulesBuilder().build();
+ this.sensorStorage = new InMemorySensorStorage();
+ this.project = new DefaultInputProject(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
+ this.module = new DefaultInputModule(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
+ this.runtime = SonarRuntimeImpl.forSonarQube(MetadataLoader.loadVersion(System2.INSTANCE), SonarQubeSide.SCANNER, MetadataLoader.loadEdition(System2.INSTANCE));
+ }
+
+ public static SensorContextTester create(File moduleBaseDir) {
+ return new SensorContextTester(moduleBaseDir.toPath());
+ }
+
+ public static SensorContextTester create(Path moduleBaseDir) {
+ return new SensorContextTester(moduleBaseDir);
+ }
+
+ @Override
+ public Settings settings() {
+ return settings;
+ }
+
+ @Override
+ public Configuration config() {
+ return new ConfigurationBridge(settings);
+ }
+
+ public SensorContextTester setSettings(Settings settings) {
+ this.settings = settings;
+ return this;
+ }
+
+ @Override
+ public DefaultFileSystem fileSystem() {
+ return fs;
+ }
+
+ public SensorContextTester setFileSystem(DefaultFileSystem fs) {
+ this.fs = fs;
+ return this;
+ }
+
+ @Override
+ public ActiveRules activeRules() {
+ return activeRules;
+ }
+
+ public SensorContextTester setActiveRules(ActiveRules activeRules) {
+ this.activeRules = activeRules;
+ return this;
+ }
+
+ /**
+ * Default value is the version of this API at compilation time. You can override it
+ * using {@link #setRuntime(SonarRuntime)} to test your Sensor behaviour.
+ */
+ @Override
+ public Version getSonarQubeVersion() {
+ return runtime().getApiVersion();
+ }
+
+ /**
+ * @see #setRuntime(SonarRuntime) to override defaults (SonarQube scanner with version
+ * of this API as used at compilation time).
+ */
+ @Override
+ public SonarRuntime runtime() {
+ return runtime;
+ }
+
+ public SensorContextTester setRuntime(SonarRuntime runtime) {
+ this.runtime = runtime;
+ return this;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @Override
+ public InputModule module() {
+ return module;
+ }
+
+ @Override
+ public InputProject project() {
+ return project;
+ }
+
+ @Override
+ public <G extends Serializable> NewMeasure<G> newMeasure() {
+ return new DefaultMeasure<>(sensorStorage);
+ }
+
+ public Collection<Measure> measures(String componentKey) {
+ return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).values();
+ }
+
+ public <G extends Serializable> Measure<G> measure(String componentKey, Metric<G> metric) {
+ return measure(componentKey, metric.key());
+ }
+
+ public <G extends Serializable> Measure<G> measure(String componentKey, String metricKey) {
+ return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).get(metricKey);
+ }
+
+ @Override
+ public NewIssue newIssue() {
+ return new DefaultIssue(project, sensorStorage);
+ }
+
+ public Collection<Issue> allIssues() {
+ return sensorStorage.allIssues;
+ }
+
+ @Override
+ public NewExternalIssue newExternalIssue() {
+ return new DefaultExternalIssue(project, sensorStorage);
+ }
+
+ @Override
+ public NewAdHocRule newAdHocRule() {
+ return new DefaultAdHocRule(sensorStorage);
+ }
+
+ public Collection<ExternalIssue> allExternalIssues() {
+ return sensorStorage.allExternalIssues;
+ }
+
+ public Collection<AdHocRule> allAdHocRules() {
+ return sensorStorage.allAdHocRules;
+ }
+
+ public Collection<AnalysisError> allAnalysisErrors() {
+ return sensorStorage.allAnalysisErrors;
+ }
+
+ @CheckForNull
+ public Integer lineHits(String fileKey, int line) {
+ return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
+ .map(c -> c.hitsByLine().get(line))
+ .flatMap(Stream::of)
+ .filter(Objects::nonNull)
+ .reduce(null, SensorContextTester::sumOrNull);
+ }
+
+ @CheckForNull
+ public static Integer sumOrNull(@Nullable Integer o1, @Nullable Integer o2) {
+ return o1 == null ? o2 : (o1 + o2);
+ }
+
+ @CheckForNull
+ public Integer conditions(String fileKey, int line) {
+ return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
+ .map(c -> c.conditionsByLine().get(line))
+ .flatMap(Stream::of)
+ .filter(Objects::nonNull)
+ .reduce(null, SensorContextTester::maxOrNull);
+ }
+
+ @CheckForNull
+ public Integer coveredConditions(String fileKey, int line) {
+ return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
+ .map(c -> c.coveredConditionsByLine().get(line))
+ .flatMap(Stream::of)
+ .filter(Objects::nonNull)
+ .reduce(null, SensorContextTester::maxOrNull);
+ }
+
+ @CheckForNull
+ public TextRange significantCodeTextRange(String fileKey, int line) {
+ if (sensorStorage.significantCodePerComponent.containsKey(fileKey)) {
+ return sensorStorage.significantCodePerComponent.get(fileKey)
+ .significantCodePerLine()
+ .get(line);
+ }
+ return null;
+
+ }
+
+ @CheckForNull
+ public static Integer maxOrNull(@Nullable Integer o1, @Nullable Integer o2) {
+ return o1 == null ? o2 : Math.max(o1, o2);
+ }
+
+ @CheckForNull
+ public List<TokensLine> cpdTokens(String componentKey) {
+ DefaultCpdTokens defaultCpdTokens = sensorStorage.cpdTokensByComponent.get(componentKey);
+ return defaultCpdTokens != null ? defaultCpdTokens.getTokenLines() : null;
+ }
+
+ @Override
+ public NewHighlighting newHighlighting() {
+ return new DefaultHighlighting(sensorStorage);
+ }
+
+ @Override
+ public NewCoverage newCoverage() {
+ return new DefaultCoverage(sensorStorage);
+ }
+
+ @Override
+ public NewCpdTokens newCpdTokens() {
+ return new DefaultCpdTokens(sensorStorage);
+ }
+
+ @Override
+ public NewSymbolTable newSymbolTable() {
+ return new DefaultSymbolTable(sensorStorage);
+ }
+
+ @Override
+ public NewAnalysisError newAnalysisError() {
+ return new DefaultAnalysisError(sensorStorage);
+ }
+
+ /**
+ * Return list of syntax highlighting applied for a given position in a file. The result is a list because in theory you
+ * can apply several styles to the same range.
+ *
+ * @param componentKey Key of the file like 'myProjectKey:src/foo.php'
+ * @param line Line you want to query
+ * @param lineOffset Offset you want to query.
+ * @return List of styles applied to this position or empty list if there is no highlighting at this position.
+ */
+ public List<TypeOfText> highlightingTypeAt(String componentKey, int line, int lineOffset) {
+ DefaultHighlighting syntaxHighlightingData = (DefaultHighlighting) sensorStorage.highlightingByComponent.get(componentKey);
+ if (syntaxHighlightingData == null) {
+ return Collections.emptyList();
+ }
+ List<TypeOfText> result = new ArrayList<>();
+ DefaultTextPointer location = new DefaultTextPointer(line, lineOffset);
+ for (SyntaxHighlightingRule sortedRule : syntaxHighlightingData.getSyntaxHighlightingRuleSet()) {
+ if (sortedRule.range().start().compareTo(location) <= 0 && sortedRule.range().end().compareTo(location) > 0) {
+ result.add(sortedRule.getTextType());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return list of symbol references ranges for the symbol at a given position in a file.
+ *
+ * @param componentKey Key of the file like 'myProjectKey:src/foo.php'
+ * @param line Line you want to query
+ * @param lineOffset Offset you want to query.
+ * @return List of references for the symbol (potentially empty) or null if there is no symbol at this position.
+ */
+ @CheckForNull
+ public Collection<TextRange> referencesForSymbolAt(String componentKey, int line, int lineOffset) {
+ DefaultSymbolTable symbolTable = sensorStorage.symbolsPerComponent.get(componentKey);
+ if (symbolTable == null) {
+ return null;
+ }
+ DefaultTextPointer location = new DefaultTextPointer(line, lineOffset);
+ for (Map.Entry<TextRange, Set<TextRange>> symbol : symbolTable.getReferencesBySymbol().entrySet()) {
+ if (symbol.getKey().start().compareTo(location) <= 0 && symbol.getKey().end().compareTo(location) > 0) {
+ return symbol.getValue();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void addContextProperty(String key, String value) {
+ sensorStorage.storeProperty(key, value);
+ }
+
+ /**
+ * @return an immutable map of the context properties defined with {@link SensorContext#addContextProperty(String, String)}.
+ * @since 6.1
+ */
+ public Map<String, String> getContextProperties() {
+ return unmodifiableMap(sensorStorage.contextProperties);
+ }
+
+ @Override
+ public void markForPublishing(InputFile inputFile) {
+ DefaultInputFile file = (DefaultInputFile) inputFile;
+ file.setPublished(true);
+ }
+
+ @Override
+ public NewSignificantCode newSignificantCode() {
+ return new DefaultSignificantCode(sensorStorage);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.highlighting.TypeOfText;
+
+public class SyntaxHighlightingRule {
+
+ private final TextRange range;
+ private final TypeOfText textType;
+
+ private SyntaxHighlightingRule(TextRange range, TypeOfText textType) {
+ this.range = range;
+ this.textType = textType;
+ }
+
+ public static SyntaxHighlightingRule create(TextRange range, TypeOfText textType) {
+ return new SyntaxHighlightingRule(range, textType);
+ }
+
+ public TextRange range() {
+ return range;
+ }
+
+ public TypeOfText getTextType() {
+ return textType;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.sensor;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import javax.annotation.Nullable;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.MessageException;
+
+/**
+ * Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction} that keeps
+ * a context of rule for better error messages. Used only when declaring rules.
+ *
+ * @see org.sonar.api.server.rule.RulesDefinition
+ */
+class DefaultDebtRemediationFunctions implements RulesDefinition.DebtRemediationFunctions {
+
+ private final String repoKey;
+ private final String key;
+
+ DefaultDebtRemediationFunctions(String repoKey, String key) {
+ this.repoKey = repoKey;
+ this.key = key;
+ }
+
+ @Override
+ public DebtRemediationFunction linear(String gapMultiplier) {
+ return create(DefaultDebtRemediationFunction.Type.LINEAR, gapMultiplier, null);
+ }
+
+ @Override
+ public DebtRemediationFunction linearWithOffset(String gapMultiplier, String baseEffort) {
+ return create(DefaultDebtRemediationFunction.Type.LINEAR_OFFSET, gapMultiplier, baseEffort);
+ }
+
+ @Override
+ public DebtRemediationFunction constantPerIssue(String baseEffort) {
+ return create(DefaultDebtRemediationFunction.Type.CONSTANT_ISSUE, null, baseEffort);
+ }
+
+ @Override
+ public DebtRemediationFunction create(DebtRemediationFunction.Type type, @Nullable String gapMultiplier, @Nullable String baseEffort) {
+ try {
+ return new DefaultDebtRemediationFunction(type, gapMultiplier, baseEffort);
+ } catch (Exception e) {
+ throw MessageException.of(String.format("The rule '%s:%s' is invalid : %s ", this.repoKey, this.key, e.getMessage()));
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
+
+public class DefaultNewParam extends RulesDefinition.NewParam {
+ private final String key;
+ private String name;
+ private String description;
+ private String defaultValue;
+ private RuleParamType type = RuleParamType.STRING;
+
+ DefaultNewParam(String key) {
+ this.key = this.name = key;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public DefaultNewParam setName(@Nullable String s) {
+ // name must never be null.
+ this.name = StringUtils.defaultIfBlank(s, key);
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setType(RuleParamType t) {
+ this.type = t;
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setDescription(@Nullable String s) {
+ this.description = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
+ @Override
+ public DefaultNewParam setDefaultValue(@Nullable String s) {
+ this.defaultValue = defaultIfEmpty(s, null);
+ return this;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String description() {
+ return description;
+ }
+
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ public RuleParamType type() {
+ return type;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+public class DefaultNewRepository implements RulesDefinition.NewRepository {
+ private final RuleDefinitionContext context;
+ private final String key;
+ private final boolean isExternal;
+ private final String language;
+ private String name;
+ private final Map<String, RulesDefinition.NewRule> newRules = new HashMap<>();
+
+ DefaultNewRepository(RuleDefinitionContext context, String key, String language, boolean isExternal) {
+ this.context = context;
+ this.key = key;
+ this.name = key;
+ this.language = language;
+ this.isExternal = isExternal;
+ }
+
+ @Override
+ public boolean isExternal() {
+ return isExternal;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ String language() {
+ return language;
+ }
+
+ Map<String, RulesDefinition.NewRule> newRules() {
+ return newRules;
+ }
+
+ String name() {
+ return name;
+ }
+
+ @Override
+ public DefaultNewRepository setName(@Nullable String s) {
+ if (StringUtils.isNotEmpty(s)) {
+ this.name = s;
+ }
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.NewRule createRule(String ruleKey) {
+ checkArgument(!newRules.containsKey(ruleKey), "The rule '%s' of repository '%s' is declared several times", ruleKey, key);
+ RulesDefinition.NewRule newRule = new DefaultNewRule(context.currentPluginKey(), key, ruleKey);
+ newRules.put(ruleKey, newRule);
+ return newRule;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.NewRule rule(String ruleKey) {
+ return newRules.get(ruleKey);
+ }
+
+ @Override
+ public Collection<RulesDefinition.NewRule> rules() {
+ return newRules.values();
+ }
+
+ @Override
+ public void done() {
+ // note that some validations can be done here, for example for
+ // verifying that at least one rule is declared
+
+ context.registerRepository(this);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("NewRepository{");
+ sb.append("key='").append(key).append('\'');
+ sb.append(", language='").append(language).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RuleTagFormat;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static java.lang.String.format;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.lang.StringUtils.isEmpty;
+import static org.apache.commons.lang.StringUtils.trimToNull;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+class DefaultNewRule extends RulesDefinition.NewRule {
+ private final String pluginKey;
+ private final String repoKey;
+ private final String key;
+ private RuleType type;
+ private String name;
+ private String htmlDescription;
+ private String markdownDescription;
+ private String internalKey;
+ private String severity = Severity.MAJOR;
+ private boolean template;
+ private RuleStatus status = RuleStatus.defaultStatus();
+ private DebtRemediationFunction debtRemediationFunction;
+ private String gapDescription;
+ private final Set<String> tags = new TreeSet<>();
+ private final Set<String> securityStandards = new TreeSet<>();
+ private final Map<String, RulesDefinition.NewParam> paramsByKey = new HashMap<>();
+ private final RulesDefinition.DebtRemediationFunctions functions;
+ private boolean activatedByDefault;
+ private RuleScope scope;
+ private final Set<RuleKey> deprecatedRuleKeys = new TreeSet<>();
+
+ DefaultNewRule(@Nullable String pluginKey, String repoKey, String key) {
+ this.pluginKey = pluginKey;
+ this.repoKey = repoKey;
+ this.key = key;
+ this.functions = new DefaultDebtRemediationFunctions(repoKey, key);
+ }
+
+ @Override
+ public String key() {
+ return this.key;
+ }
+
+ @CheckForNull
+ @Override
+ public RuleScope scope() {
+ return this.scope;
+ }
+
+ @Override
+ public DefaultNewRule setScope(RuleScope scope) {
+ this.scope = scope;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setName(String s) {
+ this.name = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setTemplate(boolean template) {
+ this.template = template;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setActivatedByDefault(boolean activatedByDefault) {
+ this.activatedByDefault = activatedByDefault;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setSeverity(String s) {
+ checkArgument(Severity.ALL.contains(s), "Severity of rule %s is not correct: %s", this, s);
+ this.severity = s;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setType(RuleType t) {
+ this.type = t;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setHtmlDescription(@Nullable String s) {
+ checkState(markdownDescription == null, "Rule '%s' already has a Markdown description", this);
+ this.htmlDescription = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setHtmlDescription(@Nullable URL classpathUrl) {
+ if (classpathUrl != null) {
+ try {
+ setHtmlDescription(IOUtils.toString(classpathUrl, UTF_8));
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to read: " + classpathUrl, e);
+ }
+ } else {
+ this.htmlDescription = null;
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setMarkdownDescription(@Nullable String s) {
+ checkState(htmlDescription == null, "Rule '%s' already has an HTML description", this);
+ this.markdownDescription = trimToNull(s);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setMarkdownDescription(@Nullable URL classpathUrl) {
+ if (classpathUrl != null) {
+ try {
+ setMarkdownDescription(IOUtils.toString(classpathUrl, UTF_8));
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to read: " + classpathUrl, e);
+ }
+ } else {
+ this.markdownDescription = null;
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setStatus(RuleStatus status) {
+ checkArgument(RuleStatus.REMOVED != status, "Status 'REMOVED' is not accepted on rule '%s'", this);
+ this.status = status;
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setDebtSubCharacteristic(@Nullable String s) {
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.DebtRemediationFunctions debtRemediationFunctions() {
+ return functions;
+ }
+
+ @Override
+ public DefaultNewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn) {
+ this.debtRemediationFunction = fn;
+ return this;
+ }
+
+ @Deprecated
+ @Override
+ public DefaultNewRule setEffortToFixDescription(@Nullable String s) {
+ return setGapDescription(s);
+ }
+
+ @Override
+ public DefaultNewRule setGapDescription(@Nullable String s) {
+ this.gapDescription = s;
+ return this;
+ }
+
+ @Override
+ public RulesDefinition.NewParam createParam(String paramKey) {
+ checkArgument(!paramsByKey.containsKey(paramKey), "The parameter '%s' is declared several times on the rule %s", paramKey, this);
+ DefaultNewParam param = new DefaultNewParam(paramKey);
+ paramsByKey.put(paramKey, param);
+ return param;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.NewParam param(String paramKey) {
+ return paramsByKey.get(paramKey);
+ }
+
+ @Override
+ public Collection<RulesDefinition.NewParam> params() {
+ return paramsByKey.values();
+ }
+
+ @Override
+ public DefaultNewRule addTags(String... list) {
+ for (String tag : list) {
+ RuleTagFormat.validate(tag);
+ tags.add(tag);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setTags(String... list) {
+ tags.clear();
+ addTags(list);
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule addOwaspTop10(RulesDefinition.OwaspTop10... standards) {
+ for (RulesDefinition.OwaspTop10 owaspTop10 : standards) {
+ String standard = "owaspTop10:" + owaspTop10.name().toLowerCase(Locale.ENGLISH);
+ securityStandards.add(standard);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule addCwe(int... nums) {
+ for (int num : nums) {
+ String standard = "cwe:" + num;
+ securityStandards.add(standard);
+ }
+ return this;
+ }
+
+ @Override
+ public DefaultNewRule setInternalKey(@Nullable String s) {
+ this.internalKey = s;
+ return this;
+ }
+
+ void validate() {
+ if (isEmpty(name)) {
+ throw new IllegalStateException(format("Name of rule %s is empty", this));
+ }
+ if (isEmpty(htmlDescription) && isEmpty(markdownDescription)) {
+ throw new IllegalStateException(format("One of HTML description or Markdown description must be defined for rule %s", this));
+ }
+ }
+
+ @Override
+ public DefaultNewRule addDeprecatedRuleKey(String repository, String key) {
+ deprecatedRuleKeys.add(RuleKey.of(repository, key));
+ return this;
+ }
+
+ String pluginKey() {
+ return pluginKey;
+ }
+
+ String repoKey() {
+ return repoKey;
+ }
+
+ RuleType type() {
+ return type;
+ }
+
+ String name() {
+ return name;
+ }
+
+ String htmlDescription() {
+ return htmlDescription;
+ }
+
+ String markdownDescription() {
+ return markdownDescription;
+ }
+
+ @CheckForNull
+ String internalKey() {
+ return internalKey;
+ }
+
+ String severity() {
+ return severity;
+ }
+
+ boolean template() {
+ return template;
+ }
+
+ RuleStatus status() {
+ return status;
+ }
+
+ DebtRemediationFunction debtRemediationFunction() {
+ return debtRemediationFunction;
+ }
+
+ String gapDescription() {
+ return gapDescription;
+ }
+
+ Set<String> tags() {
+ return tags;
+ }
+
+ Set<String> securityStandards() {
+ return securityStandards;
+ }
+
+ Map<String, RulesDefinition.NewParam> paramsByKey() {
+ return paramsByKey;
+ }
+
+ boolean activatedByDefault() {
+ return activatedByDefault;
+ }
+
+ Set<RuleKey> deprecatedRuleKeys() {
+ return deprecatedRuleKeys;
+ }
+
+ @Override
+ public String toString() {
+ return format("[repository=%s, key=%s]", repoKey, key);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+
+@Immutable
+public class DefaultParam implements RulesDefinition.Param {
+ private final String key;
+ private final String name;
+ private final String description;
+ private final String defaultValue;
+ private final RuleParamType type;
+
+ DefaultParam(DefaultNewParam newParam) {
+ this.key = newParam.key();
+ this.name = newParam.name();
+ this.description = newParam.description();
+ this.defaultValue = newParam.defaultValue();
+ this.type = newParam.type();
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ @Nullable
+ public String description() {
+ return description;
+ }
+
+ @Override
+ @Nullable
+ public String defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public RuleParamType type() {
+ return type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RulesDefinition.Param that = (RulesDefinition.Param) o;
+ return key.equals(that.key());
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.log.Loggers;
+
+import static java.lang.String.format;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Collections.unmodifiableMap;
+
+@Immutable
+class DefaultRepository implements RulesDefinition.Repository {
+ private final String key;
+ private final String language;
+ private final String name;
+ private final boolean isExternal;
+ private final Map<String, RulesDefinition.Rule> rulesByKey;
+
+ DefaultRepository(DefaultNewRepository newRepository, @Nullable RulesDefinition.Repository mergeInto) {
+ this.key = newRepository.key();
+ this.language = newRepository.language();
+ this.isExternal = newRepository.isExternal();
+ Map<String, RulesDefinition.Rule> ruleBuilder = new HashMap<>();
+ if (mergeInto != null) {
+ if (!StringUtils.equals(newRepository.language(), mergeInto.language()) || !StringUtils.equals(newRepository.key(), mergeInto.key())) {
+ throw new IllegalArgumentException(format("Bug - language and key of the repositories to be merged should be the sames: %s and %s", newRepository, mergeInto));
+ }
+ this.name = StringUtils.defaultIfBlank(mergeInto.name(), newRepository.name());
+ for (RulesDefinition.Rule rule : mergeInto.rules()) {
+ if (!newRepository.key().startsWith("common-") && ruleBuilder.containsKey(rule.key())) {
+ Loggers.get(getClass()).warn("The rule '{}' of repository '{}' is declared several times", rule.key(), mergeInto.key());
+ }
+ ruleBuilder.put(rule.key(), rule);
+ }
+ } else {
+ this.name = newRepository.name();
+ }
+ for (RulesDefinition.NewRule newRule : newRepository.newRules().values()) {
+ DefaultNewRule defaultNewRule = (DefaultNewRule) newRule;
+ defaultNewRule.validate();
+ ruleBuilder.put(newRule.key(), new DefaultRule(this, defaultNewRule));
+ }
+ this.rulesByKey = unmodifiableMap(ruleBuilder);
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String language() {
+ return language;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public boolean isExternal() {
+ return isExternal;
+ }
+
+ @Override
+ @CheckForNull
+ public RulesDefinition.Rule rule(String ruleKey) {
+ return rulesByKey.get(ruleKey);
+ }
+
+ @Override
+ public List<RulesDefinition.Rule> rules() {
+ return unmodifiableList(new ArrayList<>(rulesByKey.values()));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DefaultRepository that = (DefaultRepository) o;
+ return key.equals(that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Repository{");
+ sb.append("key='").append(key).append('\'');
+ sb.append(", language='").append(language).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.CheckForNull;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.api.server.rule.RuleTagsToTypeConverter;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static java.lang.String.format;
+import static java.util.Collections.unmodifiableList;
+
+@Immutable
+public class DefaultRule implements RulesDefinition.Rule {
+ private final String pluginKey;
+ private final RulesDefinition.Repository repository;
+ private final String repoKey;
+ private final String key;
+ private final String name;
+ private final RuleType type;
+ private final String htmlDescription;
+ private final String markdownDescription;
+ private final String internalKey;
+ private final String severity;
+ private final boolean template;
+ private final DebtRemediationFunction debtRemediationFunction;
+ private final String gapDescription;
+ private final Set<String> tags;
+ private final Set<String> securityStandards;
+ private final Map<String, RulesDefinition.Param> params;
+ private final RuleStatus status;
+ private final boolean activatedByDefault;
+ private final RuleScope scope;
+ private final Set<RuleKey> deprecatedRuleKeys;
+
+ DefaultRule(DefaultRepository repository, DefaultNewRule newRule) {
+ this.pluginKey = newRule.pluginKey();
+ this.repository = repository;
+ this.repoKey = newRule.repoKey();
+ this.key = newRule.key();
+ this.name = newRule.name();
+ this.htmlDescription = newRule.htmlDescription();
+ this.markdownDescription = newRule.markdownDescription();
+ this.internalKey = newRule.internalKey();
+ this.severity = newRule.severity();
+ this.template = newRule.template();
+ this.status = newRule.status();
+ this.debtRemediationFunction = newRule.debtRemediationFunction();
+ this.gapDescription = newRule.gapDescription();
+ this.scope = newRule.scope() == null ? RuleScope.MAIN : newRule.scope();
+ this.type = newRule.type() == null ? RuleTagsToTypeConverter.convert(newRule.tags()) : newRule.type();
+ Set<String> tagsBuilder = new TreeSet<>(newRule.tags());
+ tagsBuilder.removeAll(RuleTagsToTypeConverter.RESERVED_TAGS);
+ this.tags = Collections.unmodifiableSet(tagsBuilder);
+ this.securityStandards = Collections.unmodifiableSet(new TreeSet<>(newRule.securityStandards()));
+ Map<String, RulesDefinition.Param> paramsBuilder = new HashMap<>();
+ for (RulesDefinition.NewParam newParam : newRule.paramsByKey().values()) {
+ paramsBuilder.put(newParam.key(), new DefaultParam((DefaultNewParam) newParam));
+ }
+ this.params = Collections.unmodifiableMap(paramsBuilder);
+ this.activatedByDefault = newRule.activatedByDefault();
+ this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys()));
+ }
+
+ public RulesDefinition.Repository repository() {
+ return repository;
+ }
+
+ @Override
+ @CheckForNull
+ public String pluginKey() {
+ return pluginKey;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public RuleScope scope() {
+ return scope;
+ }
+
+ @Override
+ public RuleType type() {
+ return type;
+ }
+
+ @Override
+ public String severity() {
+ return severity;
+ }
+
+ @Override
+ @CheckForNull
+ public String htmlDescription() {
+ return htmlDescription;
+ }
+
+ @Override
+ @CheckForNull
+ public String markdownDescription() {
+ return markdownDescription;
+ }
+
+ @Override
+ public boolean template() {
+ return template;
+ }
+
+ @Override
+ public boolean activatedByDefault() {
+ return activatedByDefault;
+ }
+
+ @Override
+ public RuleStatus status() {
+ return status;
+ }
+
+ @CheckForNull
+ @Deprecated
+ @Override
+ public String debtSubCharacteristic() {
+ return null;
+ }
+
+ @CheckForNull
+ @Override
+ public DebtRemediationFunction debtRemediationFunction() {
+ return debtRemediationFunction;
+ }
+
+ @Deprecated
+ @CheckForNull
+ @Override
+ public String effortToFixDescription() {
+ return gapDescription();
+ }
+
+ @CheckForNull
+ @Override
+ public String gapDescription() {
+ return gapDescription;
+ }
+
+ @CheckForNull
+ @Override
+ public RulesDefinition.Param param(String key) {
+ return params.get(key);
+ }
+
+ @Override
+ public List<RulesDefinition.Param> params() {
+ return unmodifiableList(new ArrayList<>(params.values()));
+ }
+
+ @Override
+ public Set<String> tags() {
+ return tags;
+ }
+
+ @Override
+ public Set<String> securityStandards() {
+ return securityStandards;
+ }
+
+ @Override
+ public Set<RuleKey> deprecatedRuleKeys() {
+ return deprecatedRuleKeys;
+ }
+
+ @CheckForNull
+ @Override
+ public String internalKey() {
+ return internalKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DefaultRule other = (DefaultRule) o;
+ return key.equals(other.key) && repoKey.equals(other.repoKey);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = repoKey.hashCode();
+ result = 31 * result + key.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return format("[repository=%s, key=%s]", repoKey, key);
+ }
+}
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class RuleDefinitionContext extends RulesDefinition.Context {
+ private final Map<String, RulesDefinition.Repository> repositoriesByKey = new HashMap<>();
+ private String currentPluginKey;
+
+ @Override
+ public RulesDefinition.NewRepository createRepository(String key, String language) {
+ return new DefaultNewRepository(this, key, language, false);
+ }
+
+ @Override
+ public RulesDefinition.NewRepository createExternalRepository(String engineId, String language) {
+ return new DefaultNewRepository(this, RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, language, true);
+ }
+
+ @Override
+ @Deprecated
+ public RulesDefinition.NewRepository extendRepository(String key, String language) {
+ return createRepository(key, language);
+ }
+
+ @Override
+ @CheckForNull
+ public RulesDefinition.Repository repository(String key) {
+ return repositoriesByKey.get(key);
+ }
+
+ @Override
+ public List<RulesDefinition.Repository> repositories() {
+ return unmodifiableList(new ArrayList<>(repositoriesByKey.values()));
+ }
+
+ @Override
+ @Deprecated
+ public List<RulesDefinition.ExtendedRepository> extendedRepositories(String repositoryKey) {
+ return emptyList();
+ }
+
+ @Override
+ @Deprecated
+ public List<RulesDefinition.ExtendedRepository> extendedRepositories() {
+ return emptyList();
+ }
+
+ void registerRepository(DefaultNewRepository newRepository) {
+ RulesDefinition.Repository existing = repositoriesByKey.get(newRepository.key());
+ if (existing != null) {
+ String existingLanguage = existing.language();
+ checkState(existingLanguage.equals(newRepository.language()),
+ "The rule repository '%s' must not be defined for two different languages: %s and %s",
+ newRepository.key(), existingLanguage, newRepository.language());
+ }
+ repositoriesByKey.put(newRepository.key(), new DefaultRepository(newRepository, existing));
+ }
+
+ public String currentPluginKey() {
+ return currentPluginKey;
+ }
+
+ @Override
+ public void setCurrentPluginKey(@Nullable String pluginKey) {
+ this.currentPluginKey = pluginKey;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.server;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+import org.sonar.api.utils.System2;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+/**
+ * A subclass of {@link System2} which implementation of {@link System2#now()} always return a bigger value than the
+ * previous returned value.
+ * <p>
+ * This class is intended to be used in Unit tests.
+ * </p>
+ */
+public class AlwaysIncreasingSystem2 extends System2 {
+ private final AtomicLong now;
+ private final long increment;
+
+ private AlwaysIncreasingSystem2(Supplier<Long> initialValueSupplier, long increment) {
+ checkArgument(increment > 0, "increment must be > 0");
+ long initialValue = initialValueSupplier.get();
+ checkArgument(initialValue >= 0, "Initial value must be >= 0");
+ this.now = new AtomicLong(initialValue);
+ this.increment = increment;
+ }
+
+ public AlwaysIncreasingSystem2(long increment) {
+ this(AlwaysIncreasingSystem2::randomInitialValue, increment);
+ }
+
+ public AlwaysIncreasingSystem2(long initialValue, int increment) {
+ this(() -> initialValue, increment);
+ }
+
+ /**
+ * Values returned by {@link #now()} will start with a random value and increment by 100.
+ */
+ public AlwaysIncreasingSystem2() {
+ this(AlwaysIncreasingSystem2::randomInitialValue, 100);
+ }
+
+ @Override
+ public long now() {
+ return now.getAndAdd(increment);
+ }
+
+ private static long randomInitialValue() {
+ return (long) Math.abs(new Random().nextInt(2_000_000));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.nio.file.FileVisitResult;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.utils.TempFolder;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+public class DefaultTempFolder implements TempFolder {
+ private static final Logger LOG = Loggers.get(DefaultTempFolder.class);
+
+ private final File tempDir;
+ private final boolean deleteOnExit;
+
+ public DefaultTempFolder(File tempDir) {
+ this(tempDir, false);
+ }
+
+ public DefaultTempFolder(File tempDir, boolean deleteOnExit) {
+ this.tempDir = tempDir;
+ this.deleteOnExit = deleteOnExit;
+ }
+
+ @Override
+ public File newDir() {
+ return createTempDir(tempDir.toPath()).toFile();
+ }
+
+ private static Path createTempDir(Path baseDir) {
+ try {
+ return Files.createTempDirectory(baseDir, null);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create temp directory", e);
+ }
+ }
+
+ @Override
+ public File newDir(String name) {
+ File dir = new File(tempDir, name);
+ try {
+ FileUtils.forceMkdir(dir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create temp directory - " + dir, e);
+ }
+ return dir;
+ }
+
+ @Override
+ public File newFile() {
+ return newFile(null, null);
+ }
+
+ @Override
+ public File newFile(@Nullable String prefix, @Nullable String suffix) {
+ return createTempFile(tempDir.toPath(), prefix, suffix).toFile();
+ }
+
+ private static Path createTempFile(Path baseDir, String prefix, String suffix) {
+ try {
+ return Files.createTempFile(baseDir, prefix, suffix);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to create temp file", e);
+ }
+ }
+
+ public void clean() {
+ try {
+ if (tempDir.exists()) {
+ Files.walkFileTree(tempDir.toPath(), DeleteRecursivelyFileVisitor.INSTANCE);
+ }
+ } catch (IOException e) {
+ LOG.error("Failed to delete temp folder", e);
+ }
+ }
+
+ public void stop() {
+ if (deleteOnExit) {
+ clean();
+ }
+ }
+
+ private static final class DeleteRecursivelyFileVisitor extends SimpleFileVisitor<Path> {
+ public static final DeleteRecursivelyFileVisitor INSTANCE = new DeleteRecursivelyFileVisitor();
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.deleteIfExists(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.deleteIfExists(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.sonar.api.utils.TempFolder;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Implementation of {@link org.sonar.api.utils.TempFolder} to be used
+ * only in JUnit tests. It wraps {@link org.junit.rules.TemporaryFolder}.
+ * <br>
+ * Example:
+ * <pre>
+ * public class MyTest {
+ * @@org.junit.Rule
+ * public JUnitTempFolder temp = new JUnitTempFolder();
+ *
+ * @@org.junit.Test
+ * public void myTest() throws Exception {
+ * File dir = temp.newDir();
+ * // ...
+ * }
+ * }
+ * </pre>
+ *
+ * @since 5.1
+ */
+public class JUnitTempFolder extends ExternalResource implements TempFolder {
+
+ private final TemporaryFolder junit = new TemporaryFolder();
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return junit.apply(base, description);
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ junit.create();
+ }
+
+ @Override
+ protected void after() {
+ junit.delete();
+ }
+
+ @Override
+ public File newDir() {
+ try {
+ return junit.newFolder();
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp dir", e);
+ }
+ }
+
+ @Override
+ public File newDir(String name) {
+ try {
+ return junit.newFolder(name);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp dir", e);
+ }
+ }
+
+ @Override
+ public File newFile() {
+ try {
+ return junit.newFile();
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp file", e);
+ }
+ }
+
+ @Override
+ public File newFile(@Nullable String prefix, @Nullable String suffix) {
+ try {
+ return junit.newFile(StringUtils.defaultString(prefix) + "-" + StringUtils.defaultString(suffix));
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp file", e);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+
+public class ScannerUtils {
+
+ private ScannerUtils() {
+ }
+
+ /**
+ * Clean provided string to remove chars that are not valid as file name.
+ *
+ * @param projectKey e.g. my:file
+ */
+ public static String cleanKeyForFilename(String projectKey) {
+ String cleanKey = StringUtils.deleteWhitespace(projectKey);
+ return StringUtils.replace(cleanKey, ":", "_");
+ }
+
+ public static String encodeForUrl(@Nullable String url) {
+ try {
+ return URLEncoder.encode(url == null ? "" : url, StandardCharsets.UTF_8.name());
+
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException("Encoding not supported", e);
+ }
+ }
+
+ public static String describe(Object o) {
+ try {
+ if (o.getClass().getMethod("toString").getDeclaringClass() != Object.class) {
+ String str = o.toString();
+ if (str != null) {
+ return str;
+ }
+ }
+ } catch (Exception e) {
+ // fallback
+ }
+
+ return o.getClass().getName();
+ }
+
+ public static String pluralize(String str, int i) {
+ if (i == 1) {
+ return str;
+ }
+ return str + "s";
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.util.TimeZone;
+import org.sonar.api.utils.System2;
+
+public class TestSystem2 extends System2 {
+
+ private long now = 0L;
+ private TimeZone defaultTimeZone = getDefaultTimeZone();
+
+ public TestSystem2 setNow(long l) {
+ this.now = l;
+ return this;
+ }
+
+ @Override
+ public long now() {
+ if (now <= 0L) {
+ throw new IllegalStateException("Method setNow() was not called by test");
+ }
+ return now;
+ }
+
+ public TestSystem2 setDefaultTimeZone(TimeZone defaultTimeZone) {
+ this.defaultTimeZone = defaultTimeZone;
+ return this;
+ }
+
+ @Override
+ public TimeZone getDefaultTimeZone() {
+ return defaultTimeZone;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.io.Serializable;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+/**
+ * @since 4.2
+ */
+public class WorkDuration implements Serializable {
+
+ static final int DAY_POSITION_IN_LONG = 10_000;
+ static final int HOUR_POSITION_IN_LONG = 100;
+ static final int MINUTE_POSITION_IN_LONG = 1;
+
+ public enum UNIT {
+ DAYS, HOURS, MINUTES
+ }
+
+ private int hoursInDay;
+
+ private long durationInMinutes;
+ private int days;
+ private int hours;
+ private int minutes;
+
+ private WorkDuration(long durationInMinutes, int days, int hours, int minutes, int hoursInDay) {
+ this.durationInMinutes = durationInMinutes;
+ this.days = days;
+ this.hours = hours;
+ this.minutes = minutes;
+ this.hoursInDay = hoursInDay;
+ }
+
+ public static WorkDuration create(int days, int hours, int minutes, int hoursInDay) {
+ long durationInSeconds = 60L * days * hoursInDay;
+ durationInSeconds += 60L * hours;
+ durationInSeconds += minutes;
+ return new WorkDuration(durationInSeconds, days, hours, minutes, hoursInDay);
+ }
+
+ public static WorkDuration createFromValueAndUnit(int value, UNIT unit, int hoursInDay) {
+ switch (unit) {
+ case DAYS:
+ return create(value, 0, 0, hoursInDay);
+ case HOURS:
+ return create(0, value, 0, hoursInDay);
+ case MINUTES:
+ return create(0, 0, value, hoursInDay);
+ default:
+ throw new IllegalStateException("Cannot create work duration");
+ }
+ }
+
+ static WorkDuration createFromLong(long duration, int hoursInDay) {
+ int days = 0;
+ int hours = 0;
+ int minutes = 0;
+
+ long time = duration;
+ Long currentTime = time / WorkDuration.DAY_POSITION_IN_LONG;
+ if (currentTime > 0) {
+ days = currentTime.intValue();
+ time = time - (currentTime * WorkDuration.DAY_POSITION_IN_LONG);
+ }
+
+ currentTime = time / WorkDuration.HOUR_POSITION_IN_LONG;
+ if (currentTime > 0) {
+ hours = currentTime.intValue();
+ time = time - (currentTime * WorkDuration.HOUR_POSITION_IN_LONG);
+ }
+
+ currentTime = time / WorkDuration.MINUTE_POSITION_IN_LONG;
+ if (currentTime > 0) {
+ minutes = currentTime.intValue();
+ }
+ return WorkDuration.create(days, hours, minutes, hoursInDay);
+ }
+
+ static WorkDuration createFromMinutes(long duration, int hoursInDay) {
+ int days = (int)(duration / (double)hoursInDay / 60.0);
+ Long currentDurationInMinutes = duration - (60L * days * hoursInDay);
+ int hours = (int)(currentDurationInMinutes / 60.0);
+ currentDurationInMinutes = currentDurationInMinutes - (60L * hours);
+ return new WorkDuration(duration, days, hours, currentDurationInMinutes.intValue(), hoursInDay);
+ }
+
+ /**
+ * Return the duration in number of working days.
+ * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8).
+ */
+ public double toWorkingDays() {
+ return durationInMinutes / 60d / hoursInDay;
+ }
+
+ /**
+ * Return the duration using the following format DDHHMM, where DD is the number of days, HH is the number of months, and MM the number of minutes.
+ * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8).
+ */
+ public long toLong() {
+ int workingDays = days;
+ int workingHours = hours;
+ if (hours >= hoursInDay) {
+ int nbAdditionalDays = hours / hoursInDay;
+ workingDays += nbAdditionalDays;
+ workingHours = hours - (nbAdditionalDays * hoursInDay);
+ }
+ return 1L * workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG;
+ }
+
+ public long toMinutes() {
+ return durationInMinutes;
+ }
+
+ public WorkDuration add(@Nullable WorkDuration with) {
+ if (with != null) {
+ return WorkDuration.createFromMinutes(this.toMinutes() + with.toMinutes(), this.hoursInDay);
+ } else {
+ return this;
+ }
+ }
+
+ public WorkDuration subtract(@Nullable WorkDuration with) {
+ if (with != null) {
+ return WorkDuration.createFromMinutes(this.toMinutes() - with.toMinutes(), this.hoursInDay);
+ } else {
+ return this;
+ }
+ }
+
+ public WorkDuration multiply(int factor) {
+ return WorkDuration.createFromMinutes(this.toMinutes() * factor, this.hoursInDay);
+ }
+
+ public int days() {
+ return days;
+ }
+
+ public int hours() {
+ return hours;
+ }
+
+ public int minutes() {
+ return minutes;
+ }
+
+ int hoursInDay() {
+ return hoursInDay;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ WorkDuration that = (WorkDuration) o;
+ return durationInMinutes == that.durationInMinutes;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (durationInMinutes ^ (durationInMinutes >>> 32));
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.utils;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.ws;
+
+import java.io.InputStream;
+import org.sonar.api.server.ws.Request;
+
+public class PartImpl implements Request.Part {
+
+ private final InputStream inputStream;
+ private final String fileName;
+
+ public PartImpl(InputStream inputStream, String fileName) {
+ this.inputStream = inputStream;
+ this.fileName = fileName;
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ @Override
+ public String getFileName() {
+ return fileName;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.ws;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.io.IOUtils;
+import org.sonar.api.server.ws.LocalConnector;
+import org.sonar.api.server.ws.Request;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Fake implementation of {@link org.sonar.api.server.ws.Request} used
+ * for testing. Call the method {@link #setParam(String, String)} to
+ * emulate some parameter values.
+ */
+public class SimpleGetRequest extends Request {
+
+ private final Map<String, String[]> params = new HashMap<>();
+ private final Map<String, Part> parts = new HashMap<>();
+ private final Map<String, String> headers = new HashMap<>();
+ private String mediaType = "application/json";
+ private String path;
+
+ @Override
+ public String method() {
+ return "GET";
+ }
+
+ @Override
+ public String getMediaType() {
+ return mediaType;
+ }
+
+ public SimpleGetRequest setMediaType(String mediaType) {
+ requireNonNull(mediaType);
+ this.mediaType = mediaType;
+ return this;
+ }
+
+ @Override
+ public boolean hasParam(String key) {
+ return params.keySet().contains(key);
+ }
+
+ @Override
+ public String param(String key) {
+ String[] strings = params.get(key);
+ return strings == null || strings.length == 0 ? null : strings[0];
+ }
+
+ @Override
+ public List<String> multiParam(String key) {
+ String value = param(key);
+ return value == null ? emptyList() : singletonList(value);
+ }
+
+ @Override
+ @CheckForNull
+ public List<String> paramAsStrings(String key) {
+ String value = param(key);
+ if (value == null) {
+ return null;
+ }
+
+ return Arrays.stream(value.split(",")).map(String::trim).filter(x -> !x.isEmpty()).collect(Collectors.toList());
+ }
+
+ @Override
+ public InputStream paramAsInputStream(String key) {
+ return IOUtils.toInputStream(param(key), UTF_8);
+ }
+
+ public SimpleGetRequest setParam(String key, @Nullable String value) {
+ if (value != null) {
+ params.put(key, new String[] {value});
+ }
+ return this;
+ }
+
+ @Override
+ public Map<String, String[]> getParams() {
+ return params;
+ }
+
+ @Override
+ public Part paramAsPart(String key) {
+ return parts.get(key);
+ }
+
+ public SimpleGetRequest setPart(String key, InputStream input, String fileName) {
+ parts.put(key, new PartImpl(input, fileName));
+ return this;
+ }
+
+ @Override
+ public LocalConnector localConnector() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public SimpleGetRequest setPath(String path) {
+ this.path = path;
+ return this;
+ }
+
+ @Override
+ public Optional<String> header(String name) {
+ return Optional.ofNullable(headers.get(name));
+ }
+
+ public SimpleGetRequest setHeader(String name, String value) {
+ headers.put(name, value);
+ return this;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.ws;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.LocalConnector;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.WebService;
+
+import static java.lang.String.format;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang.StringUtils.defaultString;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+
+/**
+ * @since 4.2
+ */
+public abstract class ValidatingRequest extends Request {
+
+ private static final String COMMA_SPLITTER = ",";
+ private WebService.Action action;
+ private LocalConnector localConnector;
+
+ public void setAction(WebService.Action action) {
+ this.action = action;
+ }
+
+ public WebService.Action action() {
+ return action;
+ }
+
+ @Override
+ public LocalConnector localConnector() {
+ requireNonNull(localConnector, "Local connector has not been set");
+ return localConnector;
+ }
+
+ public void setLocalConnector(LocalConnector lc) {
+ this.localConnector = lc;
+ }
+
+ @Override
+ @CheckForNull
+ public String param(String key) {
+ WebService.Param definition = action.param(key);
+ String rawValue = readParam(key, definition);
+ String rawValueOrDefault = defaultString(rawValue, definition.defaultValue());
+ String value = rawValueOrDefault == null ? null : trim(rawValueOrDefault);
+ validateRequiredValue(key, definition, rawValue);
+ if (value == null) {
+ return null;
+ }
+ validatePossibleValues(key, value, definition);
+ validateMaximumLength(key, definition, rawValueOrDefault);
+ validateMinimumLength(key, definition, rawValueOrDefault);
+ validateMaximumValue(key, definition, value);
+ return value;
+ }
+
+ @Override
+ public List<String> multiParam(String key) {
+ WebService.Param definition = action.param(key);
+ List<String> values = readMultiParamOrDefaultValue(key, definition);
+ return validateValues(values, definition);
+ }
+
+ private static String trim(String s) {
+ int begin;
+ for (begin = 0; begin < s.length(); begin++) {
+ if (!Character.isWhitespace(s.charAt(begin))) {
+ break;
+ }
+ }
+
+ int end;
+ for (end = s.length(); end > begin; end--) {
+ if (!Character.isWhitespace(s.charAt(end - 1))) {
+ break;
+ }
+ }
+ return s.substring(begin, end);
+ }
+
+ @Override
+ @CheckForNull
+ public InputStream paramAsInputStream(String key) {
+ return readInputStreamParam(key);
+ }
+
+ @Override
+ @CheckForNull
+ public Part paramAsPart(String key) {
+ return readPart(key);
+ }
+
+ @CheckForNull
+ @Override
+ public List<String> paramAsStrings(String key) {
+ WebService.Param definition = action.param(key);
+ String value = defaultString(readParam(key, definition), definition.defaultValue());
+ if (value == null) {
+ return null;
+ }
+ List<String> values = Arrays.stream(value.split(COMMA_SPLITTER))
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .collect(Collectors.toList());
+ return validateValues(values, definition);
+ }
+
+ @CheckForNull
+ @Override
+ public <E extends Enum<E>> List<E> paramAsEnums(String key, Class<E> enumClass) {
+ List<String> values = paramAsStrings(key);
+ if (values == null) {
+ return null;
+ }
+ return values.stream()
+ .filter(s -> !s.isEmpty())
+ .map(value -> Enum.valueOf(enumClass, value))
+ .collect(Collectors.toList());
+ }
+
+ @CheckForNull
+ private String readParam(String key, @Nullable WebService.Param definition) {
+ checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key());
+ String deprecatedKey = definition.deprecatedKey();
+ return deprecatedKey != null ? defaultString(readParam(deprecatedKey), readParam(key)) : readParam(key);
+ }
+
+ private List<String> readMultiParamOrDefaultValue(String key, @Nullable WebService.Param definition) {
+ checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key());
+
+ List<String> keyValues = readMultiParam(key);
+ if (!keyValues.isEmpty()) {
+ return keyValues;
+ }
+
+ String deprecatedKey = definition.deprecatedKey();
+ List<String> deprecatedKeyValues = deprecatedKey == null ? emptyList() : readMultiParam(deprecatedKey);
+ if (!deprecatedKeyValues.isEmpty()) {
+ return deprecatedKeyValues;
+ }
+
+ String defaultValue = definition.defaultValue();
+ return defaultValue == null ? emptyList() : singletonList(defaultValue);
+ }
+
+ @CheckForNull
+ protected abstract String readParam(String key);
+
+ protected abstract List<String> readMultiParam(String key);
+
+ @CheckForNull
+ protected abstract InputStream readInputStreamParam(String key);
+
+ @CheckForNull
+ protected abstract Part readPart(String key);
+
+ private static List<String> validateValues(List<String> values, WebService.Param definition) {
+ Integer maximumValues = definition.maxValuesAllowed();
+ checkArgument(maximumValues == null || values.size() <= maximumValues, "'%s' can contains only %s values, got %s", definition.key(), maximumValues, values.size());
+ values.forEach(value -> validatePossibleValues(definition.key(), value, definition));
+ return values;
+ }
+
+ private static void validatePossibleValues(String key, String value, WebService.Param definition) {
+ Set<String> possibleValues = definition.possibleValues();
+ if (possibleValues == null) {
+ return;
+ }
+ checkArgument(possibleValues.contains(value), "Value of parameter '%s' (%s) must be one of: %s", key, value, possibleValues);
+ }
+
+ private static void validateMaximumLength(String key, WebService.Param definition, String valueOrDefault) {
+ Integer maximumLength = definition.maximumLength();
+ if (maximumLength == null) {
+ return;
+ }
+ int valueLength = valueOrDefault.length();
+ checkArgument(valueLength <= maximumLength, "'%s' length (%s) is longer than the maximum authorized (%s)", key, valueLength, maximumLength);
+ }
+
+ private static void validateMinimumLength(String key, WebService.Param definition, String valueOrDefault) {
+ Integer minimumLength = definition.minimumLength();
+ if (minimumLength == null) {
+ return;
+ }
+ int valueLength = valueOrDefault.length();
+ checkArgument(valueLength >= minimumLength, "'%s' length (%s) is shorter than the minimum authorized (%s)", key, valueLength, minimumLength);
+ }
+
+ private static void validateMaximumValue(String key, WebService.Param definition, String value) {
+ Integer maximumValue = definition.maximumValue();
+ if (maximumValue == null) {
+ return;
+ }
+ int valueAsInt = validateAsNumeric(key, value);
+ checkArgument(valueAsInt <= maximumValue, "'%s' value (%s) must be less than %s", key, valueAsInt, maximumValue);
+ }
+
+ private static void validateRequiredValue(String key, WebService.Param definition, String value) {
+ boolean required = definition.isRequired();
+ if (required) {
+ checkArgument(value != null, format(MSG_PARAMETER_MISSING, key));
+ }
+ }
+
+ private static int validateAsNumeric(String key, String value) {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException exception) {
+ throw new IllegalArgumentException(format("'%s' value '%s' cannot be parsed as an integer", key, value), exception);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.api.impl.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.config;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import java.util.function.BiConsumer;
+import java.util.stream.IntStream;
+import org.assertj.core.data.Offset;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.sonar.api.Properties;
+import org.sonar.api.Property;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.utils.DateUtils;
+
+import static java.util.Collections.singletonList;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(DataProviderRunner.class)
+public class MapSettingsTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private PropertyDefinitions definitions;
+
+ @Properties({
+ @Property(key = "hello", name = "Hello", defaultValue = "world"),
+ @Property(key = "date", name = "Date", defaultValue = "2010-05-18"),
+ @Property(key = "datetime", name = "DateTime", defaultValue = "2010-05-18T15:50:45+0100"),
+ @Property(key = "boolean", name = "Boolean", defaultValue = "true"),
+ @Property(key = "falseboolean", name = "False Boolean", defaultValue = "false"),
+ @Property(key = "integer", name = "Integer", defaultValue = "12345"),
+ @Property(key = "array", name = "Array", defaultValue = "one,two,three"),
+ @Property(key = "multi_values", name = "Array", defaultValue = "1,2,3", multiValues = true),
+ @Property(key = "sonar.jira", name = "Jira Server", type = PropertyType.PROPERTY_SET, propertySetKey = "jira"),
+ @Property(key = "newKey", name = "New key", deprecatedKey = "oldKey"),
+ @Property(key = "newKeyWithDefaultValue", name = "New key with default value", deprecatedKey = "oldKeyWithDefaultValue", defaultValue = "default_value"),
+ @Property(key = "new_multi_values", name = "New multi values", defaultValue = "1,2,3", multiValues = true, deprecatedKey = "old_multi_values")
+ })
+ private static class Init {
+ }
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void init_definitions() {
+ definitions = new PropertyDefinitions();
+ definitions.addComponent(Init.class);
+ }
+
+ @Test
+ public void set_throws_NPE_if_key_is_null() {
+ org.sonar.api.impl.config.MapSettings underTest = new org.sonar.api.impl.config.MapSettings();
+
+ expectKeyNullNPE();
+
+ underTest.set(null, randomAlphanumeric(3));
+ }
+
+ @Test
+ public void set_throws_NPE_if_value_is_null() {
+ org.sonar.api.impl.config.MapSettings underTest = new org.sonar.api.impl.config.MapSettings();
+
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("value can't be null");
+
+ underTest.set(randomAlphanumeric(3), null);
+ }
+
+ @Test
+ public void set_accepts_empty_value_and_trims_it() {
+ org.sonar.api.impl.config.MapSettings underTest = new org.sonar.api.impl.config.MapSettings();
+ Random random = new Random();
+ String key = randomAlphanumeric(3);
+
+ underTest.set(key, blank(random));
+
+ assertThat(underTest.getString(key)).isEmpty();
+ }
+
+ @Test
+ public void default_values_should_be_loaded_from_definitions() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getDefaultValue("hello")).isEqualTo("world");
+ }
+
+ @Test
+ @UseDataProvider("setPropertyCalls")
+ public void all_setProperty_methods_throws_NPE_if_key_is_null(BiConsumer<Settings, String> setPropertyCaller) {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+
+ expectKeyNullNPE();
+
+ setPropertyCaller.accept(settings, null);
+ }
+
+ @Test
+ public void set_property_string_throws_NPE_if_key_is_null() {
+ String key = randomAlphanumeric(3);
+
+ Settings underTest = new org.sonar.api.impl.config.MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
+
+ expectKeyNullNPE();
+
+ underTest.setProperty(null, new String[] {"1", "2"});
+ }
+
+ private void expectKeyNullNPE() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("key can't be null");
+ }
+
+ @Test
+ @UseDataProvider("setPropertyCalls")
+ public void all_set_property_methods_trims_key(BiConsumer<Settings, String> setPropertyCaller) {
+ Settings underTest = new org.sonar.api.impl.config.MapSettings();
+
+ Random random = new Random();
+ String blankBefore = blank(random);
+ String blankAfter = blank(random);
+ String key = randomAlphanumeric(3);
+
+ setPropertyCaller.accept(underTest, blankBefore + key + blankAfter);
+
+ assertThat(underTest.hasKey(key)).isTrue();
+ }
+
+ @Test
+ public void set_property_string_array_trims_key() {
+ String key = randomAlphanumeric(3);
+
+ Settings underTest = new org.sonar.api.impl.config.MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
+
+ Random random = new Random();
+ String blankBefore = blank(random);
+ String blankAfter = blank(random);
+
+ underTest.setProperty(blankBefore + key + blankAfter, new String[] {"1", "2"});
+
+ assertThat(underTest.hasKey(key)).isTrue();
+ }
+
+ private static String blank(Random random) {
+ StringBuilder b = new StringBuilder();
+ IntStream.range(0, random.nextInt(3)).mapToObj(s -> " ").forEach(b::append);
+ return b.toString();
+ }
+
+ @DataProvider
+ public static Object[][] setPropertyCalls() {
+ List<BiConsumer<Settings, String>> callers = Arrays.asList(
+ (settings, key) -> settings.setProperty(key, 123),
+ (settings, key) -> settings.setProperty(key, 123L),
+ (settings, key) -> settings.setProperty(key, 123.2F),
+ (settings, key) -> settings.setProperty(key, 123.2D),
+ (settings, key) -> settings.setProperty(key, false),
+ (settings, key) -> settings.setProperty(key, new Date()),
+ (settings, key) -> settings.setProperty(key, new Date(), true));
+
+ return callers.stream().map(t -> new Object[] {t}).toArray(Object[][]::new);
+ }
+
+ @Test
+ public void setProperty_methods_trims_value() {
+ Settings underTest = new org.sonar.api.impl.config.MapSettings();
+
+ Random random = new Random();
+ String blankBefore = blank(random);
+ String blankAfter = blank(random);
+ String key = randomAlphanumeric(3);
+ String value = randomAlphanumeric(3);
+
+ underTest.setProperty(key, blankBefore + value + blankAfter);
+
+ assertThat(underTest.getString(key)).isEqualTo(value);
+ }
+
+ @Test
+ public void set_property_int() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", 123);
+ assertThat(settings.getInt("foo")).isEqualTo(123);
+ assertThat(settings.getString("foo")).isEqualTo("123");
+ assertThat(settings.getBoolean("foo")).isFalse();
+ }
+
+ @Test
+ public void default_number_values_are_zero() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ assertThat(settings.getInt("foo")).isEqualTo(0);
+ assertThat(settings.getLong("foo")).isEqualTo(0L);
+ }
+
+ @Test
+ public void getInt_value_must_be_valid() {
+ thrown.expect(NumberFormatException.class);
+
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "not a number");
+ settings.getInt("foo");
+ }
+
+ @Test
+ public void all_values_should_be_trimmed_set_property() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", " FOO ");
+ assertThat(settings.getString("foo")).isEqualTo("FOO");
+ }
+
+ @Test
+ public void test_get_default_value() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getDefaultValue("unknown")).isNull();
+ }
+
+ @Test
+ public void test_get_string() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("hello", "Russia");
+ assertThat(settings.getString("hello")).isEqualTo("Russia");
+ }
+
+ @Test
+ public void setProperty_date() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ Date date = DateUtils.parseDateTime("2010-05-18T15:50:45+0100");
+ settings.setProperty("aDate", date);
+ settings.setProperty("aDateTime", date, true);
+
+ assertThat(settings.getString("aDate")).isEqualTo("2010-05-18");
+ assertThat(settings.getString("aDateTime")).startsWith("2010-05-18T");
+ }
+
+ @Test
+ public void test_get_date() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getDate("unknown")).isNull();
+ assertThat(settings.getDate("date").getDate()).isEqualTo(18);
+ assertThat(settings.getDate("date").getMonth()).isEqualTo(4);
+ }
+
+ @Test
+ public void test_get_date_not_found() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getDate("unknown")).isNull();
+ }
+
+ @Test
+ public void test_get_datetime() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getDateTime("unknown")).isNull();
+ assertThat(settings.getDateTime("datetime").getDate()).isEqualTo(18);
+ assertThat(settings.getDateTime("datetime").getMonth()).isEqualTo(4);
+ assertThat(settings.getDateTime("datetime").getMinutes()).isEqualTo(50);
+ }
+
+ @Test
+ public void test_get_double() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("from_double", 3.14159);
+ settings.setProperty("from_string", "3.14159");
+ assertThat(settings.getDouble("from_double")).isEqualTo(3.14159, Offset.offset(0.00001));
+ assertThat(settings.getDouble("from_string")).isEqualTo(3.14159, Offset.offset(0.00001));
+ assertThat(settings.getDouble("unknown")).isNull();
+ }
+
+ @Test
+ public void test_get_float() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("from_float", 3.14159f);
+ settings.setProperty("from_string", "3.14159");
+ assertThat(settings.getDouble("from_float")).isEqualTo(3.14159f, Offset.offset(0.00001));
+ assertThat(settings.getDouble("from_string")).isEqualTo(3.14159f, Offset.offset(0.00001));
+ assertThat(settings.getDouble("unknown")).isNull();
+ }
+
+ @Test
+ public void test_get_bad_float() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "bar");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("The property 'foo' is not a float value");
+ settings.getFloat("foo");
+ }
+
+ @Test
+ public void test_get_bad_double() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "bar");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("The property 'foo' is not a double value");
+ settings.getDouble("foo");
+ }
+
+ @Test
+ public void testSetNullFloat() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", (Float) null);
+ assertThat(settings.getFloat("foo")).isNull();
+ }
+
+ @Test
+ public void testSetNullDouble() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", (Double) null);
+ assertThat(settings.getDouble("foo")).isNull();
+ }
+
+ @Test
+ public void getStringArray() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ String[] array = settings.getStringArray("array");
+ assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
+ }
+
+ @Test
+ public void setStringArray() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("multi_values", new String[] {"A", "B"});
+ String[] array = settings.getStringArray("multi_values");
+ assertThat(array).isEqualTo(new String[] {"A", "B"});
+ }
+
+ @Test
+ public void setStringArrayTrimValues() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("multi_values", new String[] {" A ", " B "});
+ String[] array = settings.getStringArray("multi_values");
+ assertThat(array).isEqualTo(new String[] {"A", "B"});
+ }
+
+ @Test
+ public void setStringArrayEscapeCommas() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("multi_values", new String[] {"A,B", "C,D"});
+ String[] array = settings.getStringArray("multi_values");
+ assertThat(array).isEqualTo(new String[] {"A,B", "C,D"});
+ }
+
+ @Test
+ public void setStringArrayWithEmptyValues() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("multi_values", new String[] {"A,B", "", "C,D"});
+ String[] array = settings.getStringArray("multi_values");
+ assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
+ }
+
+ @Test
+ public void setStringArrayWithNullValues() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("multi_values", new String[] {"A,B", null, "C,D"});
+ String[] array = settings.getStringArray("multi_values");
+ assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void shouldFailToSetArrayValueOnSingleValueProperty() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("array", new String[] {"A", "B", "C"});
+ }
+
+ @Test
+ public void getStringArray_no_value() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ String[] array = settings.getStringArray("array");
+ assertThat(array).isEmpty();
+ }
+
+ @Test
+ public void shouldTrimArray() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", " one, two, three ");
+ String[] array = settings.getStringArray("foo");
+ assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
+ }
+
+ @Test
+ public void shouldKeepEmptyValuesWhenSplitting() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", " one, , two");
+ String[] array = settings.getStringArray("foo");
+ assertThat(array).isEqualTo(new String[] {"one", "", "two"});
+ }
+
+ @Test
+ public void testDefaultValueOfGetString() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getString("hello")).isEqualTo("world");
+ }
+
+ @Test
+ public void set_property_boolean() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", true);
+ settings.setProperty("bar", false);
+ assertThat(settings.getBoolean("foo")).isTrue();
+ assertThat(settings.getBoolean("bar")).isFalse();
+ assertThat(settings.getString("foo")).isEqualTo("true");
+ assertThat(settings.getString("bar")).isEqualTo("false");
+ }
+
+ @Test
+ public void ignore_case_of_boolean_values() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "true");
+ settings.setProperty("bar", "TRUE");
+ // labels in UI
+ settings.setProperty("baz", "True");
+
+ assertThat(settings.getBoolean("foo")).isTrue();
+ assertThat(settings.getBoolean("bar")).isTrue();
+ assertThat(settings.getBoolean("baz")).isTrue();
+ }
+
+ @Test
+ public void get_boolean() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ assertThat(settings.getBoolean("boolean")).isTrue();
+ assertThat(settings.getBoolean("falseboolean")).isFalse();
+ assertThat(settings.getBoolean("unknown")).isFalse();
+ assertThat(settings.getBoolean("hello")).isFalse();
+ }
+
+ @Test
+ public void shouldCreateByIntrospectingComponent() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.getDefinitions().addComponent(MyComponent.class);
+
+ // property definition has been loaded, ie for default value
+ assertThat(settings.getDefaultValue("foo")).isEqualTo("bar");
+ }
+
+ @Property(key = "foo", name = "Foo", defaultValue = "bar")
+ public static class MyComponent {
+
+ }
+
+ @Test
+ public void getStringLines_no_value() {
+ assertThat(new org.sonar.api.impl.config.MapSettings().getStringLines("foo")).hasSize(0);
+ }
+
+ @Test
+ public void getStringLines_single_line() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "the line");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"the line"});
+ }
+
+ @Test
+ public void getStringLines_linux() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "one\ntwo");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
+
+ settings.setProperty("foo", "one\ntwo\n");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
+ }
+
+ @Test
+ public void getStringLines_windows() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "one\r\ntwo");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
+
+ settings.setProperty("foo", "one\r\ntwo\r\n");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
+ }
+
+ @Test
+ public void getStringLines_mix() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("foo", "one\r\ntwo\nthree");
+ assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two", "three"});
+ }
+
+ @Test
+ public void getKeysStartingWith() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings();
+ settings.setProperty("sonar.jdbc.url", "foo");
+ settings.setProperty("sonar.jdbc.username", "bar");
+ settings.setProperty("sonar.security", "admin");
+
+ assertThat(settings.getKeysStartingWith("sonar")).containsOnly("sonar.jdbc.url", "sonar.jdbc.username", "sonar.security");
+ assertThat(settings.getKeysStartingWith("sonar.jdbc")).containsOnly("sonar.jdbc.url", "sonar.jdbc.username");
+ assertThat(settings.getKeysStartingWith("other")).hasSize(0);
+ }
+
+ @Test
+ public void should_fallback_deprecated_key_to_default_value_of_new_key() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+
+ assertThat(settings.getString("newKeyWithDefaultValue")).isEqualTo("default_value");
+ assertThat(settings.getString("oldKeyWithDefaultValue")).isEqualTo("default_value");
+ }
+
+ @Test
+ public void should_fallback_deprecated_key_to_new_key() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("newKey", "value of newKey");
+
+ assertThat(settings.getString("newKey")).isEqualTo("value of newKey");
+ assertThat(settings.getString("oldKey")).isEqualTo("value of newKey");
+ }
+
+ @Test
+ public void should_load_value_of_deprecated_key() {
+ // it's used for example when deprecated settings are set through command-line
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("oldKey", "value of oldKey");
+
+ assertThat(settings.getString("newKey")).isEqualTo("value of oldKey");
+ assertThat(settings.getString("oldKey")).isEqualTo("value of oldKey");
+ }
+
+ @Test
+ public void should_load_values_of_deprecated_key() {
+ Settings settings = new org.sonar.api.impl.config.MapSettings(definitions);
+ settings.setProperty("oldKey", "a,b");
+
+ assertThat(settings.getStringArray("newKey")).containsOnly("a", "b");
+ assertThat(settings.getStringArray("oldKey")).containsOnly("a", "b");
+ }
+
+ @Test
+ public void should_support_deprecated_props_with_multi_values() {
+ Settings settings = new MapSettings(definitions);
+ settings.setProperty("new_multi_values", new String[] {" A ", " B "});
+ assertThat(settings.getStringArray("new_multi_values")).isEqualTo(new String[] {"A", "B"});
+ assertThat(settings.getStringArray("old_multi_values")).isEqualTo(new String[] {"A", "B"});
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.config;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.Random;
+import java.util.function.Function;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.impl.config.MultivalueProperty.parseAsCsv;
+import static org.sonar.api.impl.config.MultivalueProperty.trimFieldsAndRemoveEmptyFields;
+
+@RunWith(DataProviderRunner.class)
+public class MultivaluePropertyTest {
+ private static final String[] EMPTY_STRING_ARRAY = {};
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ @UseDataProvider("testParseAsCsv")
+ public void parseAsCsv_for_coverage(String value, String[] expected) {
+ // parseAsCsv is extensively tested in org.sonar.server.config.ConfigurationProviderTest
+ assertThat(parseAsCsv("key", value))
+ .isEqualTo(parseAsCsv("key", value, Function.identity()))
+ .isEqualTo(expected);
+ }
+
+ @Test
+ public void parseAsCsv_fails_with_ISE_if_value_can_not_be_parsed() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Property: 'multi' doesn't contain a valid CSV value: '\"a ,b'");
+
+ parseAsCsv("multi", "\"a ,b");
+ }
+
+ @DataProvider
+ public static Object[][] testParseAsCsv() {
+ return new Object[][] {
+ {"a", arrayOf("a")},
+ {" a", arrayOf("a")},
+ {"a ", arrayOf("a")},
+ {" a, b", arrayOf("a", "b")},
+ {"a,b ", arrayOf("a", "b")},
+ {"a,,,b,c,,d", arrayOf("a", "b", "c", "d")},
+ {" , \n ,, \t", EMPTY_STRING_ARRAY},
+ {"\" a\"", arrayOf(" a")},
+ {"\",\"", arrayOf(",")},
+ // escaped quote in quoted field
+ {"\"\"\"\"", arrayOf("\"")}
+ };
+ }
+
+ private static String[] arrayOf(String... strs) {
+ return strs;
+ }
+
+ @Test
+ public void trimFieldsAndRemoveEmptyFields_throws_NPE_if_arg_is_null() {
+ expectedException.expect(NullPointerException.class);
+
+ trimFieldsAndRemoveEmptyFields(null);
+ }
+
+ @Test
+ @UseDataProvider("plains")
+ public void trimFieldsAndRemoveEmptyFields_ignores_EmptyFields(String str) {
+ assertThat(trimFieldsAndRemoveEmptyFields("")).isEqualTo("");
+ assertThat(trimFieldsAndRemoveEmptyFields(str)).isEqualTo(str);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + str)).isEqualTo(str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ',')).isEqualTo(str);
+ assertThat(trimFieldsAndRemoveEmptyFields(",,," + str)).isEqualTo(str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ",,,")).isEqualTo(str);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str)).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str)).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str)).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields("," + str + ",,," + str)).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(",,," + str + ",,," + str)).isEqualTo(str + ',' + str);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',')).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str + ",")).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str + ",,")).isEqualTo(str + ',' + str);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str + ',')).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(",," + str + ',' + str + ',')).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ",," + str + ',')).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str + ",,")).isEqualTo(str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(",,," + str + ",,," + str + ",,")).isEqualTo(str + ',' + str);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',' + str)).isEqualTo(str + ',' + str + ',' + str);
+ assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',' + str)).isEqualTo(str + ',' + str + ',' + str);
+ }
+
+ @DataProvider
+ public static Object[][] plains() {
+ return new Object[][] {
+ {randomAlphanumeric(1)},
+ {randomAlphanumeric(2)},
+ {randomAlphanumeric(3 + new Random().nextInt(5))}
+ };
+ }
+
+ @Test
+ @UseDataProvider("emptyAndtrimmable")
+ public void trimFieldsAndRemoveEmptyFields_ignores_empty_fields_and_trims_fields(String empty, String trimmable) {
+ String expected = trimmable.trim();
+ assertThat(empty.trim()).isEmpty();
+
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + empty)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ",," + empty)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + trimmable)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ",," + trimmable)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + trimmable + ',' + empty)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ",," + trimmable + ",,," + empty)).isEqualTo(expected);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + empty + ',' + empty)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ",," + empty + ",,," + empty)).isEqualTo(expected);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + empty + ',' + trimmable)).isEqualTo(expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(empty + ",,,," + empty + ",," + trimmable)).isEqualTo(expected);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected + ',' + expected);
+ assertThat(trimFieldsAndRemoveEmptyFields(trimmable + "," + trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected + ',' + expected);
+ }
+
+ @Test
+ public void trimAccordingToStringTrim() {
+ String str = randomAlphanumeric(4);
+ for (int i = 0; i <= ' '; i++) {
+ String prefixed = (char) i + str;
+ String suffixed = (char) i + str;
+ String both = (char) i + str + (char) i;
+ assertThat(trimFieldsAndRemoveEmptyFields(prefixed)).isEqualTo(prefixed.trim());
+ assertThat(trimFieldsAndRemoveEmptyFields(suffixed)).isEqualTo(suffixed.trim());
+ assertThat(trimFieldsAndRemoveEmptyFields(both)).isEqualTo(both.trim());
+ }
+ }
+
+ @DataProvider
+ public static Object[][] emptyAndtrimmable() {
+ Random random = new Random();
+ String oneEmpty = randomTrimmedChars(1, random);
+ String twoEmpty = randomTrimmedChars(2, random);
+ String threePlusEmpty = randomTrimmedChars(3 + random.nextInt(5), random);
+ String onePlusEmpty = randomTrimmedChars(1 + random.nextInt(5), random);
+
+ String plain = randomAlphanumeric(1);
+ String plainWithtrimmable = randomAlphanumeric(2) + onePlusEmpty + randomAlphanumeric(3);
+ String quotedWithSeparator = '"' + randomAlphanumeric(3) + ',' + randomAlphanumeric(2) + '"';
+ String quotedWithDoubleSeparator = '"' + randomAlphanumeric(3) + ",," + randomAlphanumeric(2) + '"';
+ String quotedWithtrimmable = '"' + randomAlphanumeric(3) + onePlusEmpty + randomAlphanumeric(2) + '"';
+
+ String[] empties = {oneEmpty, twoEmpty, threePlusEmpty};
+ String[] strings = {plain, plainWithtrimmable,
+ onePlusEmpty + plain, plain + onePlusEmpty, onePlusEmpty + plain + onePlusEmpty,
+ onePlusEmpty + plainWithtrimmable, plainWithtrimmable + onePlusEmpty, onePlusEmpty + plainWithtrimmable + onePlusEmpty,
+ onePlusEmpty + quotedWithSeparator, quotedWithSeparator + onePlusEmpty, onePlusEmpty + quotedWithSeparator + onePlusEmpty,
+ onePlusEmpty + quotedWithDoubleSeparator, quotedWithDoubleSeparator + onePlusEmpty, onePlusEmpty + quotedWithDoubleSeparator + onePlusEmpty,
+ onePlusEmpty + quotedWithtrimmable, quotedWithtrimmable + onePlusEmpty, onePlusEmpty + quotedWithtrimmable + onePlusEmpty
+ };
+
+ Object[][] res = new Object[empties.length * strings.length][2];
+ int i = 0;
+ for (String empty : empties) {
+ for (String string : strings) {
+ res[i][0] = empty;
+ res[i][1] = string;
+ i++;
+ }
+ }
+ return res;
+ }
+
+ @Test
+ @UseDataProvider("emptys")
+ public void trimFieldsAndRemoveEmptyFields_quotes_allow_to_preserve_fields(String empty) {
+ String quotedEmpty = '"' + empty + '"';
+
+ assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty)).isEqualTo(quotedEmpty);
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + quotedEmpty)).isEqualTo(quotedEmpty);
+ assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',')).isEqualTo(quotedEmpty);
+ assertThat(trimFieldsAndRemoveEmptyFields(',' + quotedEmpty + ',')).isEqualTo(quotedEmpty);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',' + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty);
+ assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ",," + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty);
+
+ assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',' + quotedEmpty + ',' + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty + ',' + quotedEmpty);
+ }
+
+ @DataProvider
+ public static Object[][] emptys() {
+ Random random = new Random();
+ return new Object[][] {
+ {randomTrimmedChars(1, random)},
+ {randomTrimmedChars(2, random)},
+ {randomTrimmedChars(3 + random.nextInt(5), random)}
+ };
+ }
+
+ @Test
+ public void trimFieldsAndRemoveEmptyFields_supports_escaped_quote_in_quotes() {
+ assertThat(trimFieldsAndRemoveEmptyFields("\"f\"\"oo\"")).isEqualTo("\"f\"\"oo\"");
+ assertThat(trimFieldsAndRemoveEmptyFields("\"f\"\"oo\",\"bar\"\"\"")).isEqualTo("\"f\"\"oo\",\"bar\"\"\"");
+ }
+
+ @Test
+ public void trimFieldsAndRemoveEmptyFields_does_not_fail_on_unbalanced_quotes() {
+ assertThat(trimFieldsAndRemoveEmptyFields("\"")).isEqualTo("\"");
+ assertThat(trimFieldsAndRemoveEmptyFields("\"foo")).isEqualTo("\"foo");
+ assertThat(trimFieldsAndRemoveEmptyFields("foo\"")).isEqualTo("foo\"");
+
+ assertThat(trimFieldsAndRemoveEmptyFields("\"foo\",\"")).isEqualTo("\"foo\",\"");
+ assertThat(trimFieldsAndRemoveEmptyFields("\",\"foo\"")).isEqualTo("\",\"foo\"");
+
+ assertThat(trimFieldsAndRemoveEmptyFields("\"foo\",\", ")).isEqualTo("\"foo\",\", ");
+
+ assertThat(trimFieldsAndRemoveEmptyFields(" a ,,b , c, \"foo\",\" ")).isEqualTo("a,b,c,\"foo\",\" ");
+ assertThat(trimFieldsAndRemoveEmptyFields("\" a ,,b , c, ")).isEqualTo("\" a ,,b , c, ");
+ }
+
+ private static final char[] SOME_PRINTABLE_TRIMMABLE_CHARS = {
+ ' ', '\t', '\n', '\r'
+ };
+
+ /**
+ * Result of randomTrimmedChars being used as arguments to JUnit test method through the DataProvider feature, they
+ * are printed to surefire report. Some of those chars breaks the parsing of the surefire report during sonar analysis.
+ * Therefor, we only use a subset of the trimmable chars.
+ */
+ private static String randomTrimmedChars(int length, Random random) {
+ char[] chars = new char[length];
+ for (int i = 0; i < chars.length; i++) {
+ chars[i] = SOME_PRINTABLE_TRIMMABLE_CHARS[random.nextInt(SOME_PRINTABLE_TRIMMABLE_CHARS.length)];
+ }
+ return new String(chars);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.context;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import org.sonar.api.SonarEdition;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.context.MetadataLoader;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MetadataLoaderTest {
+ private System2 system = mock(System2.class);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void load_version_from_file_in_classpath() {
+ Version version = org.sonar.api.impl.context.MetadataLoader.loadVersion(System2.INSTANCE);
+ assertThat(version).isNotNull();
+ assertThat(version.major()).isGreaterThanOrEqualTo(5);
+ }
+
+ @Test
+ public void load_edition_from_file_in_classpath() {
+ SonarEdition edition = org.sonar.api.impl.context.MetadataLoader.loadEdition(System2.INSTANCE);
+ assertThat(edition).isNotNull();
+ }
+
+ @Test
+ public void load_edition_defaults_to_community_if_file_not_found() throws MalformedURLException {
+ when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURI().toURL());
+ SonarEdition edition = org.sonar.api.impl.context.MetadataLoader.loadEdition(System2.INSTANCE);
+ assertThat(edition).isEqualTo(SonarEdition.COMMUNITY);
+ }
+
+ @Test
+ public void throw_ISE_if_edition_is_invalid() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Invalid edition found in '/sonar-edition.txt': 'TRASH'");
+
+ org.sonar.api.impl.context.MetadataLoader.parseEdition("trash");
+ }
+
+ @Test
+ public void throw_ISE_if_fail_to_load_version() throws Exception {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Can not load /sonar-api-version.txt from classpath");
+
+ when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURI().toURL());
+ MetadataLoader.loadVersion(system);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.context;
+
+import org.sonar.api.SonarEdition;
+import org.assertj.core.api.Assertions;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.SonarProduct;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
+import org.sonar.api.utils.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SonarRuntimeImplTest {
+
+ private static final Version A_VERSION = Version.parse("6.0");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void sonarQube_environment() {
+ SonarRuntime apiVersion = org.sonar.api.impl.context.SonarRuntimeImpl.forSonarQube(A_VERSION, SonarQubeSide.SCANNER, SonarEdition.COMMUNITY);
+ assertThat(apiVersion.getApiVersion()).isEqualTo(A_VERSION);
+ assertThat(apiVersion.getProduct()).isEqualTo(SonarProduct.SONARQUBE);
+ assertThat(apiVersion.getSonarQubeSide()).isEqualTo(SonarQubeSide.SCANNER);
+ }
+
+ @Test
+ public void sonarLint_environment() {
+ SonarRuntime apiVersion = org.sonar.api.impl.context.SonarRuntimeImpl.forSonarLint(A_VERSION);
+ assertThat(apiVersion.getApiVersion()).isEqualTo(A_VERSION);
+ assertThat(apiVersion.getProduct()).isEqualTo(SonarProduct.SONARLINT);
+ try {
+ apiVersion.getSonarQubeSide();
+ Assertions.fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(UnsupportedOperationException.class);
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void sonarqube_requires_side() {
+ SonarRuntimeImpl.forSonarQube(A_VERSION, null, null);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultFileSystemTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private DefaultFileSystem fs;
+
+ private File basedir;
+
+ @Before
+ public void prepare() throws Exception {
+ basedir = temp.newFolder();
+ fs = new DefaultFileSystem(basedir.toPath());
+ }
+
+ @Test
+ public void test_directories() throws Exception {
+ assertThat(fs.baseDir()).isAbsolute().isDirectory().exists();
+ assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(basedir.getCanonicalPath());
+
+ File workdir = temp.newFolder();
+ fs.setWorkDir(workdir.toPath());
+ assertThat(fs.workDir()).isAbsolute().isDirectory().exists();
+ assertThat(fs.workDir().getCanonicalPath()).isEqualTo(workdir.getCanonicalPath());
+ }
+
+ @Test
+ public void test_encoding() throws Exception {
+ fs.setEncoding(Charset.forName("ISO-8859-1"));
+ assertThat(fs.encoding()).isEqualTo(Charset.forName("ISO-8859-1"));
+ }
+
+ @Test
+ public void add_languages() {
+ assertThat(fs.languages()).isEmpty();
+
+ fs.add(new TestInputFileBuilder("foo", "src/Foo.php").setLanguage("php").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+
+ assertThat(fs.languages()).containsOnly("java", "php");
+ }
+
+ @Test
+ public void files() {
+ assertThat(fs.inputFiles(fs.predicates().all())).isEmpty();
+
+ fs.add(new TestInputFileBuilder("foo", "src/Foo.php").setLanguage("php").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Baz.java").setLanguage("java").build());
+
+ // no language
+ fs.add(new TestInputFileBuilder("foo", "src/readme.txt").build());
+
+ assertThat(fs.inputFile(fs.predicates().hasRelativePath("src/Bar.java"))).isNotNull();
+ assertThat(fs.inputFile(fs.predicates().hasRelativePath("does/not/exist"))).isNull();
+
+ assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "src/Bar.java").getAbsolutePath()))).isNotNull();
+ assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "does/not/exist").getAbsolutePath()))).isNull();
+ assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "../src/Bar.java").getAbsolutePath()))).isNull();
+
+ assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "src/Bar.java").toURI()))).isNotNull();
+ assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "does/not/exist").toURI()))).isNull();
+ assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "../src/Bar.java").toURI()))).isNull();
+
+ assertThat(fs.files(fs.predicates().all())).hasSize(4);
+ assertThat(fs.files(fs.predicates().hasLanguage("java"))).hasSize(2);
+ assertThat(fs.files(fs.predicates().hasLanguage("cobol"))).isEmpty();
+
+ assertThat(fs.hasFiles(fs.predicates().all())).isTrue();
+ assertThat(fs.hasFiles(fs.predicates().hasLanguage("java"))).isTrue();
+ assertThat(fs.hasFiles(fs.predicates().hasLanguage("cobol"))).isFalse();
+
+ assertThat(fs.inputFiles(fs.predicates().all())).hasSize(4);
+ assertThat(fs.inputFiles(fs.predicates().hasLanguage("php"))).hasSize(1);
+ assertThat(fs.inputFiles(fs.predicates().hasLanguage("java"))).hasSize(2);
+ assertThat(fs.inputFiles(fs.predicates().hasLanguage("cobol"))).isEmpty();
+
+ assertThat(fs.languages()).containsOnly("java", "php");
+ }
+
+ @Test
+ public void input_file_returns_null_if_file_not_found() {
+ assertThat(fs.inputFile(fs.predicates().hasRelativePath("src/Bar.java"))).isNull();
+ assertThat(fs.inputFile(fs.predicates().hasLanguage("cobol"))).isNull();
+ }
+
+ @Test
+ public void input_file_fails_if_too_many_results() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("expected one element");
+
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+ fs.add(new TestInputFileBuilder("foo", "src/Baz.java").setLanguage("java").build());
+
+ fs.inputFile(fs.predicates().all());
+ }
+
+ @Test
+ public void input_file_supports_non_indexed_predicates() {
+ fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
+
+ // it would fail if more than one java file
+ assertThat(fs.inputFile(fs.predicates().hasLanguage("java"))).isNotNull();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultInputDirTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void test() throws Exception {
+ File baseDir = temp.newFolder();
+ DefaultInputDir inputDir = new DefaultInputDir("ABCDE", "src")
+ .setModuleBaseDir(baseDir.toPath());
+
+ assertThat(inputDir.key()).isEqualTo("ABCDE:src");
+ assertThat(inputDir.file().getAbsolutePath()).isEqualTo(new File(baseDir, "src").getAbsolutePath());
+ assertThat(inputDir.relativePath()).isEqualTo("src");
+ assertThat(new File(inputDir.relativePath())).isRelative();
+ assertThat(inputDir.absolutePath()).endsWith("src");
+ assertThat(new File(inputDir.absolutePath())).isAbsolute();
+ }
+
+ @Test
+ public void testEqualsAndHashCode() throws Exception {
+ DefaultInputDir inputDir1 = new DefaultInputDir("ABCDE", "src");
+
+ DefaultInputDir inputDir2 = new DefaultInputDir("ABCDE", "src");
+
+ assertThat(inputDir1.equals(inputDir1)).isTrue();
+ assertThat(inputDir1.equals(inputDir2)).isTrue();
+ assertThat(inputDir1.equals("foo")).isFalse();
+
+ assertThat(inputDir1.hashCode()).isEqualTo(63545559);
+
+ assertThat(inputDir1.toString()).contains("[moduleKey=ABCDE, relative=src, basedir=null");
+
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.stream.Collectors;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+public class DefaultInputFileTest {
+
+ private static final String PROJECT_RELATIVE_PATH = "module1/src/Foo.php";
+ private static final String MODULE_RELATIVE_PATH = "src/Foo.php";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private DefaultIndexedFile indexedFile;
+
+ private Path baseDir;
+ private SensorStrategy sensorStrategy;
+
+ @Before
+ public void prepare() throws IOException {
+ baseDir = temp.newFolder().toPath();
+ sensorStrategy = new SensorStrategy();
+ indexedFile = new DefaultIndexedFile(baseDir.resolve(PROJECT_RELATIVE_PATH), "ABCDE", PROJECT_RELATIVE_PATH, MODULE_RELATIVE_PATH, InputFile.Type.TEST, "php", 0,
+ sensorStrategy);
+ }
+
+ @Test
+ public void test() throws Exception {
+
+ Metadata metadata = new Metadata(42, 42, "", new int[0], new int[0], 10);
+ DefaultInputFile inputFile = new DefaultInputFile(indexedFile, (f) -> f.setMetadata(metadata))
+ .setStatus(InputFile.Status.ADDED)
+ .setCharset(StandardCharsets.ISO_8859_1);
+
+ assertThat(inputFile.absolutePath()).endsWith("Foo.php");
+ assertThat(inputFile.filename()).isEqualTo("Foo.php");
+ assertThat(inputFile.uri()).hasPath(baseDir.resolve(PROJECT_RELATIVE_PATH).toUri().getPath());
+ assertThat(new File(inputFile.absolutePath())).isAbsolute();
+ assertThat(inputFile.language()).isEqualTo("php");
+ assertThat(inputFile.status()).isEqualTo(InputFile.Status.ADDED);
+ assertThat(inputFile.type()).isEqualTo(InputFile.Type.TEST);
+ assertThat(inputFile.lines()).isEqualTo(42);
+ assertThat(inputFile.charset()).isEqualTo(StandardCharsets.ISO_8859_1);
+
+ assertThat(inputFile.getModuleRelativePath()).isEqualTo(MODULE_RELATIVE_PATH);
+ assertThat(inputFile.getProjectRelativePath()).isEqualTo(PROJECT_RELATIVE_PATH);
+
+ sensorStrategy.setGlobal(false);
+ assertThat(inputFile.relativePath()).isEqualTo(MODULE_RELATIVE_PATH);
+ assertThat(new File(inputFile.relativePath())).isRelative();
+ sensorStrategy.setGlobal(true);
+ assertThat(inputFile.relativePath()).isEqualTo(PROJECT_RELATIVE_PATH);
+ assertThat(new File(inputFile.relativePath())).isRelative();
+ }
+
+ @Test
+ public void test_content() throws IOException {
+ Path testFile = baseDir.resolve(PROJECT_RELATIVE_PATH);
+ Files.createDirectories(testFile.getParent());
+ String content = "test é string";
+ Files.write(testFile, content.getBytes(StandardCharsets.ISO_8859_1));
+
+ assertThat(Files.readAllLines(testFile, StandardCharsets.ISO_8859_1).get(0)).hasSize(content.length());
+
+ Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10);
+
+ DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata))
+ .setStatus(InputFile.Status.ADDED)
+ .setCharset(StandardCharsets.ISO_8859_1);
+
+ assertThat(inputFile.contents()).isEqualTo(content);
+ try (InputStream inputStream = inputFile.inputStream()) {
+ String result = new BufferedReader(new InputStreamReader(inputStream, inputFile.charset())).lines().collect(Collectors.joining());
+ assertThat(result).isEqualTo(content);
+ }
+
+ }
+
+ @Test
+ public void test_content_exclude_bom() throws IOException {
+ Path testFile = baseDir.resolve(PROJECT_RELATIVE_PATH);
+ Files.createDirectories(testFile.getParent());
+ try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(testFile.toFile()), StandardCharsets.UTF_8))) {
+ out.write('\ufeff');
+ }
+ String content = "test é string €";
+ Files.write(testFile, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
+
+ assertThat(Files.readAllLines(testFile, StandardCharsets.UTF_8).get(0)).hasSize(content.length() + 1);
+
+ Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10);
+
+ DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata))
+ .setStatus(InputFile.Status.ADDED)
+ .setCharset(StandardCharsets.UTF_8);
+
+ assertThat(inputFile.contents()).isEqualTo(content);
+ try (InputStream inputStream = inputFile.inputStream()) {
+ String result = new BufferedReader(new InputStreamReader(inputStream, inputFile.charset())).lines().collect(Collectors.joining());
+ assertThat(result).isEqualTo(content);
+ }
+
+ }
+
+ @Test
+ public void test_equals_and_hashcode() throws Exception {
+ DefaultInputFile f1 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
+ DefaultInputFile f1a = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
+ DefaultInputFile f2 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Bar.php", null), (f) -> mock(Metadata.class));
+
+ assertThat(f1).isEqualTo(f1);
+ assertThat(f1).isEqualTo(f1a);
+ assertThat(f1).isNotEqualTo(f2);
+ assertThat(f1.equals("foo")).isFalse();
+ assertThat(f1.equals(null)).isFalse();
+
+ assertThat(f1.hashCode()).isEqualTo(f1.hashCode());
+ assertThat(f1.hashCode()).isEqualTo(f1a.hashCode());
+ }
+
+ @Test
+ public void test_toString() throws Exception {
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
+ assertThat(file.toString()).isEqualTo(MODULE_RELATIVE_PATH);
+ }
+
+ @Test
+ public void checkValidPointer() {
+ Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+ assertThat(file.newPointer(1, 0).line()).isEqualTo(1);
+ assertThat(file.newPointer(1, 0).lineOffset()).isEqualTo(0);
+ // Don't fail
+ file.newPointer(1, 9);
+ file.newPointer(2, 0);
+ file.newPointer(2, 5);
+
+ try {
+ file.newPointer(0, 1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("0 is not a valid line for a file");
+ }
+ try {
+ file.newPointer(3, 1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("3 is not a valid line for pointer. File src/Foo.php has 2 line(s)");
+ }
+ try {
+ file.newPointer(1, -1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("-1 is not a valid line offset for a file");
+ }
+ try {
+ file.newPointer(1, 10);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("10 is not a valid line offset for pointer. File src/Foo.php has 9 character(s) at line 1");
+ }
+ }
+
+ @Test
+ public void checkValidPointerUsingGlobalOffset() {
+ Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {8, 15}, 16);
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+ assertThat(file.newPointer(0).line()).isEqualTo(1);
+ assertThat(file.newPointer(0).lineOffset()).isEqualTo(0);
+
+ assertThat(file.newPointer(9).line()).isEqualTo(1);
+ // Ignore eol characters
+ assertThat(file.newPointer(9).lineOffset()).isEqualTo(8);
+
+ assertThat(file.newPointer(10).line()).isEqualTo(2);
+ assertThat(file.newPointer(10).lineOffset()).isEqualTo(0);
+
+ assertThat(file.newPointer(15).line()).isEqualTo(2);
+ assertThat(file.newPointer(15).lineOffset()).isEqualTo(5);
+
+ assertThat(file.newPointer(16).line()).isEqualTo(2);
+ // Ignore eol characters
+ assertThat(file.newPointer(16).lineOffset()).isEqualTo(5);
+
+ try {
+ file.newPointer(-1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("-1 is not a valid offset for a file");
+ }
+
+ try {
+ file.newPointer(17);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("17 is not a valid offset for file src/Foo.php. Max offset is 16");
+ }
+ }
+
+ @Test
+ public void checkValidRange() {
+ Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde"));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+
+ assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 1)).start().line()).isEqualTo(1);
+ // Don't fail
+ file.newRange(file.newPointer(1, 0), file.newPointer(1, 1));
+ file.newRange(file.newPointer(1, 0), file.newPointer(1, 9));
+ file.newRange(file.newPointer(1, 0), file.newPointer(2, 0));
+ assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 5))).isEqualTo(file.newRange(0, 15));
+
+ try {
+ file.newRange(file.newPointer(1, 0), file.newPointer(1, 0));
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Start pointer [line=1, lineOffset=0] should be before end pointer [line=1, lineOffset=0]");
+ }
+ try {
+ file.newRange(file.newPointer(1, 0), file.newPointer(1, 10));
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("10 is not a valid line offset for pointer. File src/Foo.php has 9 character(s) at line 1");
+ }
+ }
+
+ @Test
+ public void selectLine() {
+ Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde\n\nabc"));
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+
+ assertThat(file.selectLine(1).start().line()).isEqualTo(1);
+ assertThat(file.selectLine(1).start().lineOffset()).isEqualTo(0);
+ assertThat(file.selectLine(1).end().line()).isEqualTo(1);
+ assertThat(file.selectLine(1).end().lineOffset()).isEqualTo(9);
+
+ // Don't fail when selecting empty line
+ assertThat(file.selectLine(3).start().line()).isEqualTo(3);
+ assertThat(file.selectLine(3).start().lineOffset()).isEqualTo(0);
+ assertThat(file.selectLine(3).end().line()).isEqualTo(3);
+ assertThat(file.selectLine(3).end().lineOffset()).isEqualTo(0);
+
+ try {
+ file.selectLine(5);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).hasMessage("5 is not a valid line for pointer. File src/Foo.php has 4 line(s)");
+ }
+ }
+
+ @Test
+ public void checkValidRangeUsingGlobalOffset() {
+ Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+ TextRange newRange = file.newRange(10, 13);
+ assertThat(newRange.start().line()).isEqualTo(2);
+ assertThat(newRange.start().lineOffset()).isEqualTo(0);
+ assertThat(newRange.end().line()).isEqualTo(2);
+ assertThat(newRange.end().lineOffset()).isEqualTo(3);
+ }
+
+ @Test
+ public void testRangeOverlap() {
+ Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
+ DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
+ // Don't fail
+ assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)))).isTrue();
+ assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isTrue();
+ assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 1), file.newPointer(1, 2)))).isFalse();
+ assertThat(file.newRange(file.newPointer(1, 2), file.newPointer(1, 3)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isFalse();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultInputModuleTest {
+
+ private static final String FILE_1 = "file1";
+ private static final String TEST_1 = "test1";
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void check_getters() throws IOException {
+ ProjectDefinition def = ProjectDefinition.create();
+ def.setKey("moduleKey");
+ File baseDir = temp.newFolder();
+ Path src = baseDir.toPath().resolve(FILE_1);
+ Files.createFile(src);
+ Path test = baseDir.toPath().resolve(TEST_1);
+ Files.createFile(test);
+ def.setBaseDir(baseDir);
+ File workDir = temp.newFolder();
+ def.setWorkDir(workDir);
+ def.setSources(FILE_1);
+ def.setTests(TEST_1);
+ DefaultInputModule module = new DefaultInputModule(def);
+
+ assertThat(module.key()).isEqualTo("moduleKey");
+ assertThat(module.definition()).isEqualTo(def);
+ assertThat(module.getBranch()).isNull();
+ assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
+ assertThat(module.getKeyWithBranch()).isEqualTo("moduleKey");
+ assertThat(module.getWorkDir()).isEqualTo(workDir.toPath());
+ assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
+ assertThat(module.getSourceDirsOrFiles().get()).containsExactlyInAnyOrder(src);
+ assertThat(module.getTestDirsOrFiles().get()).containsExactlyInAnyOrder(test);
+ assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
+
+ assertThat(module.isFile()).isFalse();
+ }
+
+ @Test
+ public void no_sources() throws IOException {
+ ProjectDefinition def = ProjectDefinition.create();
+ def.setKey("moduleKey");
+ File baseDir = temp.newFolder();
+ Path src = baseDir.toPath().resolve(FILE_1);
+ Files.createFile(src);
+ Path test = baseDir.toPath().resolve(TEST_1);
+ Files.createFile(test);
+ def.setBaseDir(baseDir);
+ File workDir = temp.newFolder();
+ def.setWorkDir(workDir);
+ DefaultInputModule module = new DefaultInputModule(def);
+
+ assertThat(module.key()).isEqualTo("moduleKey");
+ assertThat(module.definition()).isEqualTo(def);
+ assertThat(module.getBranch()).isNull();
+ assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
+ assertThat(module.getKeyWithBranch()).isEqualTo("moduleKey");
+ assertThat(module.getWorkDir()).isEqualTo(workDir.toPath());
+ assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
+ assertThat(module.getSourceDirsOrFiles()).isNotPresent();
+ assertThat(module.getTestDirsOrFiles()).isNotPresent();
+ assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
+
+ assertThat(module.isFile()).isFalse();
+ }
+
+ @Test
+ public void working_directory_should_be_hidden() throws IOException {
+ ProjectDefinition def = ProjectDefinition.create();
+ File workDir = temp.newFolder(".sonar");
+ def.setWorkDir(workDir);
+ File baseDir = temp.newFolder();
+ def.setBaseDir(baseDir);
+ DefaultInputModule module = new DefaultInputModule(def);
+ assertThat(workDir.isHidden()).isTrue();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultInputProjectTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void testGetters() throws IOException {
+ ProjectDefinition def = ProjectDefinition.create();
+ def.setKey("projectKey");
+ def.setName("projectName");
+ File baseDir = temp.newFolder();
+ def.setBaseDir(baseDir);
+ def.setDescription("desc");
+ File workDir = temp.newFolder();
+ def.setWorkDir(workDir);
+ def.setSources("file1");
+ def.setTests("test1");
+ AbstractProjectOrModule project = new DefaultInputProject(def);
+
+ assertThat(project.key()).isEqualTo("projectKey");
+ assertThat(project.getName()).isEqualTo("projectName");
+ assertThat(project.getOriginalName()).isEqualTo("projectName");
+ assertThat(project.definition()).isEqualTo(def);
+ assertThat(project.getBranch()).isNull();
+ assertThat(project.getBaseDir()).isEqualTo(baseDir.toPath());
+ assertThat(project.getKeyWithBranch()).isEqualTo("projectKey");
+ assertThat(project.getDescription()).isEqualTo("desc");
+ assertThat(project.getWorkDir()).isEqualTo(workDir.toPath());
+ assertThat(project.getEncoding()).isEqualTo(Charset.defaultCharset());
+
+ assertThat(project.properties()).hasSize(5);
+
+ assertThat(project.isFile()).isFalse();
+ }
+
+ @Test
+ public void testEncoding() throws IOException {
+ ProjectDefinition def = ProjectDefinition.create();
+ def.setKey("projectKey");
+ def.setName("projectName");
+ File baseDir = temp.newFolder();
+ def.setBaseDir(baseDir);
+ def.setProjectVersion("version");
+ def.setDescription("desc");
+ File workDir = temp.newFolder();
+ def.setWorkDir(workDir);
+ def.setSources("file1");
+ def.setProperty("sonar.sourceEncoding", "UTF-16");
+ AbstractProjectOrModule project = new DefaultInputProject(def);
+
+ assertThat(project.getEncoding()).isEqualTo(StandardCharsets.UTF_16);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.Nullable;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+
+import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+public class FileMetadataTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Test
+ public void empty_file() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.touch(tempFile);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(1);
+ assertThat(metadata.nonBlankLines()).isEqualTo(0);
+ assertThat(metadata.hash()).isNotEmpty();
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(0);
+ assertThat(metadata.isEmpty()).isTrue();
+ }
+
+ @Test
+ public void windows_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\r\nbar\r\nbaz", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(3);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 8, 13);
+ assertThat(metadata.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void read_with_wrong_encoding() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "marker´s\n", Charset.forName("cp1252"));
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(2);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("marker\ufffds\n"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 9);
+ }
+
+ @Test
+ public void non_ascii_utf_8() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "föo\r\nbà r\r\n\u1D11Ebaßz\r\n", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbà r\n\u1D11Ebaßz\n"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18);
+ }
+
+ @Test
+ public void non_ascii_utf_16() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "föo\r\nbà r\r\n\u1D11Ebaßz\r\n", StandardCharsets.UTF_16, true);
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_16, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbà r\n\u1D11Ebaßz\n".getBytes(StandardCharsets.UTF_8)));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18);
+ }
+
+ @Test
+ public void unix_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\nbaz", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(3);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11);
+ assertThat(metadata.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void unix_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\nbaz\n", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12);
+ }
+
+ @Test
+ public void mac_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\rbar\rbaz", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(3);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11);
+ }
+
+ @Test
+ public void mac_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\rbar\rbaz\r", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12);
+ }
+
+ @Test
+ public void mix_of_newlines_with_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\r\nbaz\n", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9, 13);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12, 13);
+ }
+
+ @Test
+ public void several_new_lines() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\n\n\nbar", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(2);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\n\n\nbar"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 5, 6);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 4, 5, 9);
+ }
+
+ @Test
+ public void mix_of_newlines_without_latest_eol() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "foo\nbar\r\nbaz", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(3);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12);
+ }
+
+ @Test
+ public void start_with_newline() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "\nfoo\nbar\r\nbaz", StandardCharsets.UTF_8, true);
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
+ assertThat(metadata.lines()).isEqualTo(4);
+ assertThat(metadata.nonBlankLines()).isEqualTo(3);
+ assertThat(metadata.hash()).isEqualTo(md5Hex("\nfoo\nbar\nbaz"));
+ assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 1, 5, 10);
+ assertThat(metadata.originalLineEndOffsets()).containsOnly(0, 4, 8, 13);
+ }
+
+ @Test
+ public void ignore_whitespace_when_computing_line_hashes() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, " foo\nb ar\r\nbaz \t", StandardCharsets.UTF_8, true);
+
+ DefaultInputFile f = new TestInputFileBuilder("foo", tempFile.getName())
+ .setModuleBaseDir(tempFile.getParentFile().toPath())
+ .setCharset(StandardCharsets.UTF_8)
+ .build();
+ FileMetadata.computeLineHashesForIssueTracking(f, new FileMetadata.LineHashConsumer() {
+
+ @Override
+ public void consume(int lineIdx, @Nullable byte[] hash) {
+ switch (lineIdx) {
+ case 1:
+ assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("foo"));
+ break;
+ case 2:
+ assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("bar"));
+ break;
+ case 3:
+ assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("baz"));
+ break;
+ default:
+ fail("Invalid line");
+ }
+ }
+ });
+ }
+
+ @Test
+ public void dont_fail_on_empty_file() throws Exception {
+ File tempFile = temp.newFile();
+ FileUtils.write(tempFile, "", StandardCharsets.UTF_8, true);
+
+ DefaultInputFile f = new TestInputFileBuilder("foo", tempFile.getName())
+ .setModuleBaseDir(tempFile.getParentFile().toPath())
+ .setCharset(StandardCharsets.UTF_8)
+ .build();
+ FileMetadata.computeLineHashesForIssueTracking(f, new FileMetadata.LineHashConsumer() {
+
+ @Override
+ public void consume(int lineIdx, @Nullable byte[] hash) {
+ switch (lineIdx) {
+ case 1:
+ assertThat(hash).isNull();
+ break;
+ default:
+ fail("Invalid line");
+ }
+ }
+ });
+ }
+
+ @Test
+ public void line_feed_is_included_into_hash() throws Exception {
+ File file1 = temp.newFile();
+ FileUtils.write(file1, "foo\nbar\n", StandardCharsets.UTF_8, true);
+
+ // same as file1, except an additional return carriage
+ File file1a = temp.newFile();
+ FileUtils.write(file1a, "foo\r\nbar\n", StandardCharsets.UTF_8, true);
+
+ File file2 = temp.newFile();
+ FileUtils.write(file2, "foo\nbar", StandardCharsets.UTF_8, true);
+
+ String hash1 = new FileMetadata().readMetadata(new FileInputStream(file1), StandardCharsets.UTF_8, file1.getName()).hash();
+ String hash1a = new FileMetadata().readMetadata(new FileInputStream(file1a), StandardCharsets.UTF_8, file1a.getName()).hash();
+ String hash2 = new FileMetadata().readMetadata(new FileInputStream(file2), StandardCharsets.UTF_8, file2.getName()).hash();
+
+ assertThat(hash1).isEqualTo(hash1a);
+ assertThat(hash1).isNotEqualTo(hash2);
+ }
+
+ @Test
+ public void binary_file_with_unmappable_character() throws Exception {
+ File woff = new File(this.getClass().getResource("glyphicons-halflings-regular.woff").toURI());
+
+ Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(woff), StandardCharsets.UTF_8, woff.getAbsolutePath());
+
+ assertThat(metadata.lines()).isEqualTo(135);
+ assertThat(metadata.nonBlankLines()).isEqualTo(133);
+ assertThat(metadata.hash()).isNotEmpty();
+
+ assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains("Invalid character encountered in file");
+ assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains(
+ "glyphicons-halflings-regular.woff at line 1 for encoding UTF-8. Please fix file content or configure the encoding to be used using property 'sonar.sourceEncoding'.");
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+import org.sonar.api.impl.fs.Metadata;
+
+public class MetadataTest {
+ @Test
+ public void testRoundtrip() {
+ org.sonar.api.impl.fs.Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 3}, new int[] {2, 4}, 5);
+ assertThat(metadata.isEmpty()).isFalse();
+ assertThat(metadata.lines()).isEqualTo(10);
+ assertThat(metadata.nonBlankLines()).isEqualTo(20);
+ assertThat(metadata.originalLineStartOffsets()).isEqualTo(new int[] {1, 3});
+ assertThat(metadata.originalLineEndOffsets()).isEqualTo(new int[] {2, 4});
+ assertThat(metadata.lastValidOffset()).isEqualTo(5);
+ assertThat(metadata.hash()).isEqualTo("hash");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.IndexedFile;
+import org.sonar.api.impl.fs.DefaultIndexedFile;
+import org.sonar.api.impl.fs.PathPattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PathPatternTest {
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ private Path baseDir;
+
+ @Before
+ public void setUp() throws IOException {
+ baseDir = temp.newFolder().toPath();
+ }
+
+ @Test
+ public void match_relative_path() {
+ org.sonar.api.impl.fs.PathPattern pattern = org.sonar.api.impl.fs.PathPattern.create("**/*Foo.java");
+ assertThat(pattern.toString()).isEqualTo("**/*Foo.java");
+
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.java", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isTrue();
+
+ // case sensitive by default
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
+
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
+ }
+
+ @Test
+ public void match_relative_path_and_insensitive_file_extension() throws Exception {
+ org.sonar.api.impl.fs.PathPattern pattern = org.sonar.api.impl.fs.PathPattern.create("**/*Foo.java");
+
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isFalse();
+ }
+
+ @Test
+ public void match_absolute_path() throws Exception {
+ org.sonar.api.impl.fs.PathPattern pattern = org.sonar.api.impl.fs.PathPattern.create("file:**/src/main/**Foo.java");
+ assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
+
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.java", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isTrue();
+
+ // case sensitive by default
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
+
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
+ }
+
+ @Test
+ public void match_absolute_path_and_insensitive_file_extension() throws Exception {
+ org.sonar.api.impl.fs.PathPattern pattern = org.sonar.api.impl.fs.PathPattern.create("file:**/src/main/**Foo.java");
+ assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
+
+ IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isTrue();
+
+ indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.JAVA", null);
+ assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isFalse();
+ }
+
+ @Test
+ public void create_array_of_patterns() {
+ org.sonar.api.impl.fs.PathPattern[] patterns = PathPattern.create(new String[] {
+ "**/src/main/**Foo.java",
+ "file:**/src/main/**Bar.java"
+ });
+ assertThat(patterns).hasSize(2);
+ assertThat(patterns[0].toString()).isEqualTo("**/src/main/**Foo.java");
+ assertThat(patterns[1].toString()).isEqualTo("file:**/src/main/**Bar.java");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile.Status;
+import org.sonar.api.batch.fs.InputFile.Type;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestInputFileBuilderTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void setContent() throws IOException {
+ DefaultInputFile file = TestInputFileBuilder.create("module", "invalidPath")
+ .setContents("my content")
+ .setCharset(StandardCharsets.UTF_8)
+ .build();
+ assertThat(file.contents()).isEqualTo("my content");
+ assertThat(IOUtils.toString(file.inputStream())).isEqualTo("my content");
+ }
+
+ @Test
+ public void testGetters() {
+ DefaultInputFile file = TestInputFileBuilder.create("module", new File("baseDir"), new File("baseDir", "path"))
+ .setStatus(Status.SAME)
+ .setType(Type.MAIN)
+ .build();
+
+ assertThat(file.type()).isEqualTo(Type.MAIN);
+ assertThat(file.status()).isEqualTo(Status.SAME);
+ assertThat(file.isPublished()).isTrue();
+ assertThat(file.type()).isEqualTo(Type.MAIN);
+ assertThat(file.relativePath()).isEqualTo("path");
+ assertThat(file.absolutePath()).isEqualTo("baseDir/path");
+
+ }
+
+ @Test
+ public void testCreateInputModule() throws IOException {
+ File baseDir = temp.newFolder();
+ AbstractProjectOrModule module = TestInputFileBuilder.newDefaultInputModule("key", baseDir);
+ assertThat(module.key()).isEqualTo("key");
+ assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.charhandler;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class IntArrayListTest {
+
+ @Test
+ public void addElements() {
+ IntArrayList list = new IntArrayList();
+ assertThat(list.trimAndGet()).isEmpty();
+ list.add(1);
+ list.add(2);
+ assertThat(list.trimAndGet()).containsExactly(1, 2);
+ }
+
+ @Test
+ public void trimIfNeeded() {
+ IntArrayList list = new IntArrayList();
+ list.add(1);
+ list.add(2);
+ assertThat(list.trimAndGet()).isSameAs(list.trimAndGet());
+ }
+
+ @Test
+ public void grow() {
+ // Default capacity is 10
+ IntArrayList list = new IntArrayList();
+ for (int i = 1; i <= 11; i++) {
+ list.add(i);
+ }
+ assertThat(list.trimAndGet()).hasSize(11);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.util.Arrays;
+import org.junit.Test;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.fs.PathPattern;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AndPredicateTest {
+
+ @Test
+ public void flattenNestedAnd() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("foo3/**"));
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ AndPredicate.create(Arrays.asList(pathPatternPredicate2, pathPatternPredicate3))));
+ assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2, pathPatternPredicate3);
+ }
+
+ @Test
+ public void applyPredicates() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo/file1"));
+ PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("**"));
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ AndPredicate.create(Arrays.asList(pathPatternPredicate2, pathPatternPredicate3))));
+
+ InputFile file1 = TestInputFileBuilder.create("module", "foo/file1").build();
+ InputFile file2 = TestInputFileBuilder.create("module", "foo2/file1").build();
+ InputFile file3 = TestInputFileBuilder.create("module", "foo/file2").build();
+
+ assertThat(andPredicate.apply(file1)).isTrue();
+ assertThat(andPredicate.apply(file2)).isFalse();
+ assertThat(andPredicate.apply(file3)).isFalse();
+ }
+
+ @Test
+ public void filterIndex() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo/file1"));
+ PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("**"));
+
+ InputFile file1 = TestInputFileBuilder.create("module", "foo/file1").build();
+ InputFile file2 = TestInputFileBuilder.create("module", "foo2/file1").build();
+ InputFile file3 = TestInputFileBuilder.create("module", "foo/file2").build();
+
+ FileSystem.Index index = mock(FileSystem.Index.class);
+ when(index.inputFiles()).thenReturn(Arrays.asList(file1, file2, file3));
+
+ OptimizedFilePredicate andPredicate = (OptimizedFilePredicate) AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ AndPredicate.create(Arrays.asList(pathPatternPredicate2, pathPatternPredicate3))));
+
+ assertThat(andPredicate.get(index)).containsOnly(file1);
+ }
+
+ @Test
+ public void sortPredicatesByPriority() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ RelativePathPredicate relativePathPredicate = new RelativePathPredicate("foo");
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ relativePathPredicate, pathPatternPredicate2));
+ assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(relativePathPredicate, pathPatternPredicate1, pathPatternPredicate2);
+ }
+
+ @Test
+ public void simplifyAndExpressionsWhenEmpty() {
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList());
+ assertThat(andPredicate).isEqualTo(TruePredicate.TRUE);
+ }
+
+ @Test
+ public void simplifyAndExpressionsWhenTrue() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ TruePredicate.TRUE, pathPatternPredicate2));
+ assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2);
+ }
+
+ @Test
+ public void simplifyAndExpressionsWhenFalse() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ FilePredicate andPredicate = AndPredicate.create(Arrays.asList(pathPatternPredicate1,
+ FalsePredicate.FALSE, pathPatternPredicate2));
+ assertThat(andPredicate).isEqualTo(FalsePredicate.FALSE);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputFile.Status;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultFilePredicatesTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private Path moduleBasePath;
+
+ @Before
+ public void setUp() throws IOException {
+ moduleBasePath = temp.newFolder().toPath();
+ }
+
+ InputFile javaFile;
+ FilePredicates predicates;
+
+ @Before
+ public void before() throws IOException {
+ predicates = new DefaultFilePredicates(temp.newFolder().toPath());
+ javaFile = new TestInputFileBuilder("foo", "src/main/java/struts/Action.java")
+ .setModuleBaseDir(moduleBasePath)
+ .setLanguage("java")
+ .setStatus(Status.SAME)
+ .build();
+
+ }
+
+ @Test
+ public void all() {
+ assertThat(predicates.all().apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void none() {
+ assertThat(predicates.none().apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void matches_inclusion_pattern() {
+ assertThat(predicates.matchesPathPattern("src/main/**/Action.java").apply(javaFile)).isTrue();
+ assertThat(predicates.matchesPathPattern("Action.java").apply(javaFile)).isFalse();
+ assertThat(predicates.matchesPathPattern("src/**/*.php").apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void matches_inclusion_patterns() {
+ assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isTrue();
+ assertThat(predicates.matchesPathPatterns(new String[] {}).apply(javaFile)).isTrue();
+ assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void does_not_match_exclusion_pattern() {
+ assertThat(predicates.doesNotMatchPathPattern("src/main/**/Action.java").apply(javaFile)).isFalse();
+ assertThat(predicates.doesNotMatchPathPattern("Action.java").apply(javaFile)).isTrue();
+ assertThat(predicates.doesNotMatchPathPattern("src/**/*.php").apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void does_not_match_exclusion_patterns() {
+ assertThat(predicates.doesNotMatchPathPatterns(new String[] {}).apply(javaFile)).isTrue();
+ assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isTrue();
+ assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_relative_path() {
+ assertThat(predicates.hasRelativePath("src/main/java/struts/Action.java").apply(javaFile)).isTrue();
+ assertThat(predicates.hasRelativePath("src/main/java/struts/Other.java").apply(javaFile)).isFalse();
+
+ // path is normalized
+ assertThat(predicates.hasRelativePath("src/main/java/../java/struts/Action.java").apply(javaFile)).isTrue();
+
+ assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\Action.java").apply(javaFile)).isTrue();
+ assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\Other.java").apply(javaFile)).isFalse();
+ assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\..\\struts\\Action.java").apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void has_absolute_path() throws Exception {
+ String path = javaFile.file().getAbsolutePath();
+ assertThat(predicates.hasAbsolutePath(path).apply(javaFile)).isTrue();
+ assertThat(predicates.hasAbsolutePath(path.replaceAll("/", "\\\\")).apply(javaFile)).isTrue();
+
+ assertThat(predicates.hasAbsolutePath(temp.newFile().getAbsolutePath()).apply(javaFile)).isFalse();
+ assertThat(predicates.hasAbsolutePath("src/main/java/struts/Action.java").apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_uri() throws Exception {
+ URI uri = javaFile.uri();
+ assertThat(predicates.hasURI(uri).apply(javaFile)).isTrue();
+
+ assertThat(predicates.hasURI(temp.newFile().toURI()).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_path() throws Exception {
+ // is relative path
+ assertThat(predicates.hasPath("src/main/java/struts/Action.java").apply(javaFile)).isTrue();
+ assertThat(predicates.hasPath("src/main/java/struts/Other.java").apply(javaFile)).isFalse();
+
+ // is absolute path
+ String path = javaFile.file().getAbsolutePath();
+ assertThat(predicates.hasAbsolutePath(path).apply(javaFile)).isTrue();
+ assertThat(predicates.hasPath(temp.newFile().getAbsolutePath()).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void is_file() throws Exception {
+ // relative file
+ assertThat(predicates.is(new File(javaFile.relativePath())).apply(javaFile)).isTrue();
+
+ // absolute file
+ assertThat(predicates.is(javaFile.file()).apply(javaFile)).isTrue();
+ assertThat(predicates.is(javaFile.file().getAbsoluteFile()).apply(javaFile)).isTrue();
+ assertThat(predicates.is(new File(javaFile.file().toURI())).apply(javaFile)).isTrue();
+ assertThat(predicates.is(temp.newFile()).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_language() {
+ assertThat(predicates.hasLanguage("java").apply(javaFile)).isTrue();
+ assertThat(predicates.hasLanguage("php").apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_languages() {
+ assertThat(predicates.hasLanguages(Arrays.asList("java", "php")).apply(javaFile)).isTrue();
+ assertThat(predicates.hasLanguages(Arrays.asList("cobol", "php")).apply(javaFile)).isFalse();
+ assertThat(predicates.hasLanguages(Collections.<String>emptyList()).apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void has_type() {
+ assertThat(predicates.hasType(InputFile.Type.MAIN).apply(javaFile)).isTrue();
+ assertThat(predicates.hasType(InputFile.Type.TEST).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void has_status() {
+ assertThat(predicates.hasAnyStatus().apply(javaFile)).isTrue();
+ assertThat(predicates.hasStatus(InputFile.Status.SAME).apply(javaFile)).isTrue();
+ assertThat(predicates.hasStatus(InputFile.Status.ADDED).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void not() {
+ assertThat(predicates.not(predicates.hasType(InputFile.Type.MAIN)).apply(javaFile)).isFalse();
+ assertThat(predicates.not(predicates.hasType(InputFile.Type.TEST)).apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void and() {
+ // empty
+ assertThat(predicates.and().apply(javaFile)).isTrue();
+ assertThat(predicates.and(new FilePredicate[0]).apply(javaFile)).isTrue();
+ assertThat(predicates.and(Collections.<FilePredicate>emptyList()).apply(javaFile)).isTrue();
+
+ // two arguments
+ assertThat(predicates.and(predicates.all(), predicates.all()).apply(javaFile)).isTrue();
+ assertThat(predicates.and(predicates.all(), predicates.none()).apply(javaFile)).isFalse();
+ assertThat(predicates.and(predicates.none(), predicates.all()).apply(javaFile)).isFalse();
+
+ // collection
+ assertThat(predicates.and(Arrays.asList(predicates.all(), predicates.all())).apply(javaFile)).isTrue();
+ assertThat(predicates.and(Arrays.asList(predicates.all(), predicates.none())).apply(javaFile)).isFalse();
+
+ // array
+ assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
+ assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void or() {
+ // empty
+ assertThat(predicates.or().apply(javaFile)).isTrue();
+ assertThat(predicates.or(new FilePredicate[0]).apply(javaFile)).isTrue();
+ assertThat(predicates.or(Collections.<FilePredicate>emptyList()).apply(javaFile)).isTrue();
+
+ // two arguments
+ assertThat(predicates.or(predicates.all(), predicates.all()).apply(javaFile)).isTrue();
+ assertThat(predicates.or(predicates.all(), predicates.none()).apply(javaFile)).isTrue();
+ assertThat(predicates.or(predicates.none(), predicates.all()).apply(javaFile)).isTrue();
+ assertThat(predicates.or(predicates.none(), predicates.none()).apply(javaFile)).isFalse();
+
+ // collection
+ assertThat(predicates.or(Arrays.asList(predicates.all(), predicates.all())).apply(javaFile)).isTrue();
+ assertThat(predicates.or(Arrays.asList(predicates.all(), predicates.none())).apply(javaFile)).isTrue();
+ assertThat(predicates.or(Arrays.asList(predicates.none(), predicates.none())).apply(javaFile)).isFalse();
+
+ // array
+ assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
+ assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isTrue();
+ assertThat(predicates.or(new FilePredicate[] {predicates.none(), predicates.none()}).apply(javaFile)).isFalse();
+ }
+
+ @Test
+ public void hasFilename() {
+ assertThat(predicates.hasFilename("Action.java").apply(javaFile)).isTrue();
+ }
+
+ @Test
+ public void hasExtension() {
+ assertThat(predicates.hasExtension("java").apply(javaFile)).isTrue();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.impl.fs.predicates.FileExtensionPredicate.getExtension;
+
+public class FileExtensionPredicateTest {
+
+ @Test
+ public void should_match_correct_extension() throws IOException {
+ FileExtensionPredicate predicate = new FileExtensionPredicate("bat");
+ assertThat(predicate.apply(mockWithName("prog.bat"))).isTrue();
+ assertThat(predicate.apply(mockWithName("prog.bat.bat"))).isTrue();
+ }
+
+ @Test
+ public void should_not_match_incorrect_extension() throws IOException {
+ FileExtensionPredicate predicate = new FileExtensionPredicate("bat");
+ assertThat(predicate.apply(mockWithName("prog.batt"))).isFalse();
+ assertThat(predicate.apply(mockWithName("prog.abat"))).isFalse();
+ assertThat(predicate.apply(mockWithName("prog."))).isFalse();
+ assertThat(predicate.apply(mockWithName("prog.bat."))).isFalse();
+ assertThat(predicate.apply(mockWithName("prog.bat.batt"))).isFalse();
+ assertThat(predicate.apply(mockWithName("prog"))).isFalse();
+ }
+
+ @Test
+ public void should_match_correct_extension_case_insensitively() throws IOException {
+ FileExtensionPredicate predicate = new FileExtensionPredicate("jAVa");
+ assertThat(predicate.apply(mockWithName("Program.java"))).isTrue();
+ assertThat(predicate.apply(mockWithName("Program.JAVA"))).isTrue();
+ assertThat(predicate.apply(mockWithName("Program.Java"))).isTrue();
+ assertThat(predicate.apply(mockWithName("Program.JaVa"))).isTrue();
+ }
+
+ @Test
+ public void test_empty_extension() {
+ assertThat(getExtension("prog")).isEmpty();
+ assertThat(getExtension("prog.")).isEmpty();
+ assertThat(getExtension(".")).isEmpty();
+ }
+
+ private InputFile mockWithName(String filename) throws IOException {
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.filename()).thenReturn(filename);
+ return inputFile;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import java.io.IOException;
+import java.util.Collections;
+import org.junit.Test;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class FilenamePredicateTest {
+ @Test
+ public void should_match_file_by_filename() throws IOException {
+ String filename = "some name";
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.filename()).thenReturn(filename);
+
+ assertThat(new FilenamePredicate(filename).apply(inputFile)).isTrue();
+ }
+
+ @Test
+ public void should_not_match_file_by_different_filename() throws IOException {
+ String filename = "some name";
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.filename()).thenReturn(filename + "x");
+
+ assertThat(new FilenamePredicate(filename).apply(inputFile)).isFalse();
+ }
+
+ @Test
+ public void should_find_matching_file_in_index() throws IOException {
+ String filename = "some name";
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.filename()).thenReturn(filename);
+
+ FileSystem.Index index = mock(FileSystem.Index.class);
+ when(index.getFilesByName(filename)).thenReturn(Collections.singleton(inputFile));
+
+ assertThat(new FilenamePredicate(filename).get(index)).containsOnly(inputFile);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.junit.Test;
+import org.sonar.api.batch.fs.FilePredicate;
+
+import java.util.Arrays;
+import org.sonar.api.impl.fs.PathPattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class OrPredicateTest {
+
+ @Test
+ public void flattenNestedOr() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("foo3/**"));
+ FilePredicate orPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
+ OrPredicate.create(Arrays.asList(pathPatternPredicate2, pathPatternPredicate3))));
+ assertThat(((OrPredicate) orPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2, pathPatternPredicate3);
+ }
+
+ @Test
+ public void simplifyOrExpressionsWhenEmpty() {
+ FilePredicate orPredicate = OrPredicate.create(Arrays.asList());
+ assertThat(orPredicate).isEqualTo(TruePredicate.TRUE);
+ }
+
+ @Test
+ public void simplifyOrExpressionsWhenFalse() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ FilePredicate andPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
+ FalsePredicate.FALSE, pathPatternPredicate2));
+ assertThat(((OrPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2);
+ }
+
+ @Test
+ public void simplifyAndExpressionsWhenTrue() {
+ PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
+ PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
+ FilePredicate andPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
+ TruePredicate.TRUE, pathPatternPredicate2));
+ assertThat(andPredicate).isEqualTo(TruePredicate.TRUE);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.fs.predicates;
+
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RelativePathPredicateTest {
+ @Test
+ public void returns_false_when_path_is_invalid() {
+ RelativePathPredicate predicate = new RelativePathPredicate("..");
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.relativePath()).thenReturn("path");
+ assertThat(predicate.apply(inputFile)).isFalse();
+ }
+
+ @Test
+ public void returns_true_if_matches() {
+ RelativePathPredicate predicate = new RelativePathPredicate("path");
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.relativePath()).thenReturn("path");
+ assertThat(predicate.apply(inputFile)).isTrue();
+ }
+
+ @Test
+ public void returns_false_if_doesnt_match() {
+ RelativePathPredicate predicate = new RelativePathPredicate("path1");
+ InputFile inputFile = mock(InputFile.class);
+ when(inputFile.relativePath()).thenReturn("path2");
+ assertThat(predicate.apply(inputFile)).isFalse();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import java.util.LinkedList;
+import java.util.List;
+import org.junit.Test;
+import org.sonar.api.batch.rule.NewRule;
+import org.sonar.api.impl.rule.DefaultRules;
+import org.sonar.api.rule.RuleKey;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultRulesTest {
+ @Test
+ public void testRepeatedInternalKey() {
+ List<NewRule> newRules = new LinkedList<>();
+ newRules.add(createRule("key1", "repo", "internal"));
+ newRules.add(createRule("key2", "repo", "internal"));
+
+ DefaultRules rules = new DefaultRules(newRules);
+ assertThat(rules.findByInternalKey("repo", "internal")).hasSize(2);
+ assertThat(rules.find(RuleKey.of("repo", "key1"))).isNotNull();
+ assertThat(rules.find(RuleKey.of("repo", "key2"))).isNotNull();
+ assertThat(rules.findByRepository("repo")).hasSize(2);
+ }
+
+ @Test
+ public void testNonExistingKey() {
+ List<NewRule> newRules = new LinkedList<>();
+ newRules.add(createRule("key1", "repo", "internal"));
+ newRules.add(createRule("key2", "repo", "internal"));
+
+ DefaultRules rules = new DefaultRules(newRules);
+ assertThat(rules.findByInternalKey("xx", "xx")).hasSize(0);
+ assertThat(rules.find(RuleKey.of("xxx", "xx"))).isNull();
+ assertThat(rules.findByRepository("xxxx")).hasSize(0);
+ }
+
+ @Test
+ public void testRepeatedRule() {
+ List<NewRule> newRules = new LinkedList<>();
+ newRules.add(createRule("key", "repo", "internal"));
+ newRules.add(createRule("key", "repo", "internal"));
+
+ DefaultRules rules = new DefaultRules(newRules);
+ assertThat(rules.find(RuleKey.of("repo", "key"))).isNotNull();
+ }
+
+ private NewRule createRule(String key, String repo, String internalKey) {
+ RuleKey ruleKey = RuleKey.of(repo, key);
+ NewRule newRule = new NewRule(ruleKey);
+ newRule.setInternalKey(internalKey);
+
+ return newRule;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.rule;
+
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.rule.NewRule;
+import org.sonar.api.batch.rule.Rule;
+import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.impl.rule.RulesBuilder;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RulesBuilderTest {
+ @org.junit.Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void no_rules() {
+ RulesBuilder builder = new RulesBuilder();
+ Rules rules = builder.build();
+ assertThat(rules.findAll()).isEmpty();
+ }
+
+ @Test
+ public void build_rules() {
+ RulesBuilder builder = new RulesBuilder();
+ NewRule newSquid1 = builder.add(RuleKey.of("squid", "S0001"));
+ newSquid1.setName("Detect bug");
+ newSquid1.setDescription("Detect potential bug");
+ newSquid1.setInternalKey("foo=bar");
+ newSquid1.setSeverity(org.sonar.api.rule.Severity.CRITICAL);
+ newSquid1.setStatus(RuleStatus.BETA);
+ newSquid1.addParam("min");
+ newSquid1.addParam("max").setDescription("Maximum");
+ // most simple rule
+ builder.add(RuleKey.of("squid", "S0002"));
+ builder.add(RuleKey.of("findbugs", "NPE"));
+
+ Rules rules = builder.build();
+
+ assertThat(rules.findAll()).hasSize(3);
+ assertThat(rules.findByRepository("squid")).hasSize(2);
+ assertThat(rules.findByRepository("findbugs")).hasSize(1);
+ assertThat(rules.findByRepository("unknown")).isEmpty();
+
+ Rule squid1 = rules.find(RuleKey.of("squid", "S0001"));
+ assertThat(squid1.key().repository()).isEqualTo("squid");
+ assertThat(squid1.key().rule()).isEqualTo("S0001");
+ assertThat(squid1.name()).isEqualTo("Detect bug");
+ assertThat(squid1.description()).isEqualTo("Detect potential bug");
+ assertThat(squid1.internalKey()).isEqualTo("foo=bar");
+ assertThat(squid1.status()).isEqualTo(RuleStatus.BETA);
+ assertThat(squid1.severity()).isEqualTo(org.sonar.api.rule.Severity.CRITICAL);
+ assertThat(squid1.params()).hasSize(2);
+ assertThat(squid1.param("min").key()).isEqualTo("min");
+ assertThat(squid1.param("min").description()).isNull();
+ assertThat(squid1.param("max").key()).isEqualTo("max");
+ assertThat(squid1.param("max").description()).isEqualTo("Maximum");
+
+ Rule squid2 = rules.find(RuleKey.of("squid", "S0002"));
+ assertThat(squid2.key().repository()).isEqualTo("squid");
+ assertThat(squid2.key().rule()).isEqualTo("S0002");
+ assertThat(squid2.description()).isNull();
+ assertThat(squid2.internalKey()).isNull();
+ assertThat(squid2.status()).isEqualTo(RuleStatus.defaultStatus());
+ assertThat(squid2.severity()).isEqualTo(Severity.defaultSeverity());
+ assertThat(squid2.params()).isEmpty();
+ }
+
+ @Test
+ public void fail_to_add_twice_the_same_rule() {
+ RulesBuilder builder = new RulesBuilder();
+ builder.add(RuleKey.of("squid", "S0001"));
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Rule 'squid:S0001' already exists");
+
+ builder.add(RuleKey.of("squid", "S0001"));
+ }
+
+ @Test
+ public void fail_to_add_twice_the_same_param() {
+ RulesBuilder builder = new RulesBuilder();
+ NewRule newRule = builder.add(RuleKey.of("squid", "S0001"));
+ newRule.addParam("min");
+ newRule.addParam("max");
+
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Parameter 'min' already exists on rule 'squid:S0001'");
+
+ newRule.addParam("min");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.batch.sensor.rule.NewAdHocRule;
+import org.sonar.api.rules.RuleType;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultAdHocRuleTest {
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void store() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+ rule.save();
+
+ assertThat(rule.engineId()).isEqualTo("engine");
+ assertThat(rule.ruleId()).isEqualTo("ruleId");
+ assertThat(rule.name()).isEqualTo("name");
+ assertThat(rule.description()).isEqualTo("desc");
+ assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(rule.type()).isEqualTo(RuleType.CODE_SMELL);
+
+ verify(storage).store(any(DefaultAdHocRule.class));
+ }
+
+
+ @Test
+ public void description_is_optional() {
+ SensorStorage storage = mock(SensorStorage.class);
+ new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL)
+ .save();
+
+ verify(storage).store(any(DefaultAdHocRule.class));
+ }
+
+ @Test
+ public void fail_to_store_if_no_engine_id() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId(" ")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Engine id is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_rule_id() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId(" ")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Rule id is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_name() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name(" ")
+ .description("desc")
+ .severity(Severity.BLOCKER)
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Name is mandatory");
+ rule.save();
+ }
+
+
+ @Test
+ public void fail_to_store_if_no_severity() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .type(RuleType.CODE_SMELL);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Severity is mandatory");
+ rule.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_type() {
+ SensorStorage storage = mock(SensorStorage.class);
+ NewAdHocRule rule = new DefaultAdHocRule(storage)
+ .engineId("engine")
+ .ruleId("ruleId")
+ .name("name")
+ .description("desc")
+ .severity(Severity.BLOCKER);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Type is mandatory");
+ rule.save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextPointer;
+import org.sonar.api.batch.sensor.error.NewAnalysisError;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+public class DefaultAnalysisErrorTest {
+ private InputFile inputFile;
+ private SensorStorage storage;
+ private TextPointer textPointer;
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Before
+ public void setUp() {
+ inputFile = new TestInputFileBuilder("module1", "src/File.java").build();
+ textPointer = new DefaultTextPointer(5, 2);
+ storage = mock(SensorStorage.class);
+ }
+
+ @Test
+ public void test_analysis_error() {
+ DefaultAnalysisError analysisError = new DefaultAnalysisError(storage);
+ analysisError.onFile(inputFile)
+ .at(textPointer)
+ .message("msg");
+
+ assertThat(analysisError.location()).isEqualTo(textPointer);
+ assertThat(analysisError.message()).isEqualTo("msg");
+ assertThat(analysisError.inputFile()).isEqualTo(inputFile);
+ }
+
+ @Test
+ public void test_save() {
+ DefaultAnalysisError analysisError = new DefaultAnalysisError(storage);
+ analysisError.onFile(inputFile).save();
+
+ verify(storage).store(analysisError);
+ verifyNoMoreInteractions(storage);
+ }
+
+ @Test
+ public void test_no_storage() {
+ exception.expect(NullPointerException.class);
+ DefaultAnalysisError analysisError = new DefaultAnalysisError();
+ analysisError.onFile(inputFile).save();
+ }
+
+ @Test
+ public void test_validation() {
+ try {
+ new DefaultAnalysisError(storage).onFile(null);
+ fail("Expected exception");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ NewAnalysisError error = new DefaultAnalysisError(storage).onFile(inputFile);
+ try {
+ error.onFile(inputFile);
+ fail("Expected exception");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+
+ error = new DefaultAnalysisError(storage).at(textPointer);
+ try {
+ error.at(textPointer);
+ fail("Expected exception");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+
+ try {
+ new DefaultAnalysisError(storage).save();
+ fail("Expected exception");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+public class DefaultCpdTokensTest {
+ private final SensorStorage sensorStorage = mock(SensorStorage.class);
+
+ private final DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
+ .setLines(2)
+ .setOriginalLineStartOffsets(new int[] {0, 50})
+ .setOriginalLineEndOffsets(new int[] {49, 100})
+ .setLastValidOffset(101)
+ .build();
+
+ @Test
+ public void save_no_tokens() {
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile);
+
+ tokens.save();
+
+ verify(sensorStorage).store(tokens);
+
+ assertThat(tokens.inputFile()).isEqualTo(inputFile);
+ }
+
+ @Test
+ public void save_one_token() {
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
+
+ tokens.save();
+
+ verify(sensorStorage).store(tokens);
+
+ assertThat(tokens.getTokenLines()).extracting("value", "startLine", "hashCode", "startUnit", "endUnit").containsExactly(tuple("foo", 1, "foo".hashCode(), 1, 1));
+ }
+
+ @Test
+ public void handle_exclusions() {
+ inputFile.setExcludedForDuplication(true);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
+
+ tokens.save();
+
+ verifyZeroInteractions(sensorStorage);
+
+ assertThat(tokens.getTokenLines()).isEmpty();
+ }
+
+ @Test
+ public void dont_save_for_test_files() {
+ DefaultInputFile testInputFile = new TestInputFileBuilder("foo", "src/Foo.java")
+ .setLines(2)
+ .setOriginalLineStartOffsets(new int[] {0, 50})
+ .setOriginalLineEndOffsets(new int[] {49, 100})
+ .setLastValidOffset(101)
+ .setType(InputFile.Type.TEST)
+ .build();
+
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(testInputFile)
+ .addToken(testInputFile.newRange(1, 2, 1, 5), "foo");
+
+ tokens.save();
+ verifyZeroInteractions(sensorStorage);
+ assertThat(tokens.getTokenLines()).isEmpty();
+ }
+
+ @Test
+ public void save_many_tokens() {
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 2, 1, 5), "foo")
+ .addToken(inputFile.newRange(1, 6, 1, 10), "bar")
+ .addToken(inputFile.newRange(1, 20, 1, 25), "biz")
+ .addToken(inputFile.newRange(2, 1, 2, 10), "next");
+
+ tokens.save();
+
+ verify(sensorStorage).store(tokens);
+
+ assertThat(tokens.getTokenLines())
+ .extracting("value", "startLine", "hashCode", "startUnit", "endUnit")
+ .containsExactly(
+ tuple("foobarbiz", 1, "foobarbiz".hashCode(), 1, 3),
+ tuple("next", 2, "next".hashCode(), 4, 4));
+ }
+
+ @Test
+ public void basic_validation() {
+ SensorStorage sensorStorage = mock(SensorStorage.class);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage);
+ try {
+ tokens.save();
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Call onFile() first");
+ }
+ try {
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Call onFile() first");
+ }
+ try {
+ tokens.addToken(null, "foo");
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Range should not be null");
+ }
+ try {
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), null);
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Image should not be null");
+ }
+ }
+
+ @Test
+ public void validate_tokens_order() {
+ SensorStorage sensorStorage = mock(SensorStorage.class);
+ DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(1, 6, 1, 10), "bar");
+
+ try {
+ tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertThat(e).hasMessage("Tokens of file src/Foo.java should be provided in order.\n" +
+ "Previous token: Range[from [line=1, lineOffset=6] to [line=1, lineOffset=10]]\n" +
+ "Last token: Range[from [line=1, lineOffset=2] to [line=1, lineOffset=5]]");
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.issue.DefaultIssueLocation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultExternalIssueTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private DefaultInputProject project;
+
+ @Before
+ public void setup() throws IOException {
+ project = new DefaultInputProject(ProjectDefinition.create()
+ .setKey("foo")
+ .setBaseDir(temp.newFolder())
+ .setWorkDir(temp.newFolder()));
+ }
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
+ .initMetadata("Foo\nBar\n")
+ .build();
+
+ @Test
+ public void build_file_issue() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(1))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .remediationEffortMinutes(10l)
+ .type(RuleType.BUG)
+ .severity(Severity.BLOCKER);
+
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_repo", "rule"));
+ assertThat(issue.engineId()).isEqualTo("repo");
+ assertThat(issue.ruleId()).isEqualTo("rule");
+ assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
+ assertThat(issue.remediationEffort()).isEqualTo(10l);
+ assertThat(issue.type()).isEqualTo(RuleType.BUG);
+ assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
+
+ issue.save();
+
+ verify(storage).store(issue);
+ }
+
+ @Test
+ public void fail_to_store_if_no_type() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(1))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .remediationEffortMinutes(10l)
+ .severity(Severity.BLOCKER);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Type is mandatory");
+ issue.save();
+ }
+
+ @Test
+ public void fail_to_store_if_primary_location_is_not_a_file() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(mock(InputComponent.class))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .remediationEffortMinutes(10l)
+ .severity(Severity.BLOCKER);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("External issues must be located in files");
+ issue.save();
+ }
+
+ @Test
+ public void fail_to_store_if_primary_location_has_no_message() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(1)))
+ .forRule(RuleKey.of("repo", "rule"))
+ .remediationEffortMinutes(10l)
+ .type(RuleType.BUG)
+ .severity(Severity.BLOCKER);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("External issues must have a message");
+ issue.save();
+ }
+
+ @Test
+ public void fail_to_store_if_no_severity() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(1))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .remediationEffortMinutes(10l)
+ .type(RuleType.BUG);
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Severity is mandatory");
+ issue.save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Collection;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.DefaultTextRange;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonar.api.batch.sensor.highlighting.TypeOfText.COMMENT;
+import static org.sonar.api.batch.sensor.highlighting.TypeOfText.CPP_DOC;
+import static org.sonar.api.batch.sensor.highlighting.TypeOfText.KEYWORD;
+
+public class DefaultHighlightingTest {
+
+ private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java")
+ .setLines(2)
+ .setOriginalLineStartOffsets(new int[] {0, 50})
+ .setOriginalLineEndOffsets(new int[] {49, 100})
+ .setLastValidOffset(101)
+ .build();
+
+ private Collection<SyntaxHighlightingRule> highlightingRules;
+
+ @Rule
+ public ExpectedException throwable = ExpectedException.none();
+
+ @Before
+ public void setUpSampleRules() {
+
+ DefaultHighlighting highlightingDataBuilder = new DefaultHighlighting(mock(SensorStorage.class))
+ .onFile(INPUT_FILE)
+ .highlight(0, 10, COMMENT)
+ .highlight(1, 10, 1, 12, KEYWORD)
+ .highlight(24, 38, KEYWORD)
+ .highlight(42, 50, KEYWORD)
+ .highlight(24, 65, CPP_DOC)
+ .highlight(12, 20, COMMENT);
+
+ highlightingDataBuilder.save();
+
+ highlightingRules = highlightingDataBuilder.getSyntaxHighlightingRuleSet();
+ }
+
+ @Test
+ public void should_register_highlighting_rule() {
+ assertThat(highlightingRules).hasSize(6);
+ }
+
+ private static TextRange rangeOf(int startLine, int startOffset, int endLine, int endOffset) {
+ return new DefaultTextRange(new DefaultTextPointer(startLine, startOffset), new DefaultTextPointer(endLine, endOffset));
+ }
+
+ @Test
+ public void should_order_by_start_then_end_offset() {
+ assertThat(highlightingRules).extracting("range", TextRange.class).containsExactly(
+ rangeOf(1, 0, 1, 10),
+ rangeOf(1, 10, 1, 12),
+ rangeOf(1, 12, 1, 20),
+ rangeOf(1, 24, 2, 15),
+ rangeOf(1, 24, 1, 38),
+ rangeOf(1, 42, 2, 0));
+ assertThat(highlightingRules).extracting("textType").containsExactly(COMMENT, KEYWORD, COMMENT, CPP_DOC, KEYWORD, KEYWORD);
+ }
+
+ @Test
+ public void should_support_overlapping() {
+ new DefaultHighlighting(mock(SensorStorage.class))
+ .onFile(INPUT_FILE)
+ .highlight(0, 15, KEYWORD)
+ .highlight(8, 12, CPP_DOC)
+ .save();
+ }
+
+ @Test
+ public void should_prevent_start_equal_end() {
+ throwable.expect(IllegalArgumentException.class);
+ throwable
+ .expectMessage("Unable to highlight file");
+
+ new DefaultHighlighting(mock(SensorStorage.class))
+ .onFile(INPUT_FILE)
+ .highlight(10, 10, KEYWORD)
+ .save();
+ }
+
+ @Test
+ public void should_prevent_boudaries_overlapping() {
+ throwable.expect(IllegalStateException.class);
+ throwable
+ .expectMessage("Cannot register highlighting rule for characters at Range[from [line=1, lineOffset=8] to [line=1, lineOffset=15]] as it overlaps at least one existing rule");
+
+ new DefaultHighlighting(mock(SensorStorage.class))
+ .onFile(INPUT_FILE)
+ .highlight(0, 10, KEYWORD)
+ .highlight(8, 15, KEYWORD)
+ .save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.apache.commons.lang.StringUtils;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.issue.DefaultIssueLocation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.rules.ExpectedException.none;
+
+public class DefaultIssueLocationTest {
+
+ @Rule
+ public ExpectedException thrown = none();
+
+ private InputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
+ .initMetadata("Foo\nBar\n")
+ .build();
+
+ @Test
+ public void should_build() {
+ assertThat(new DefaultIssueLocation()
+ .on(inputFile)
+ .message("pipo bimbo")
+ .message()
+ ).isEqualTo("pipo bimbo");
+ }
+
+ @Test
+ public void not_allowed_to_call_on_twice() {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("on() already called");
+ new DefaultIssueLocation()
+ .on(inputFile)
+ .on(inputFile)
+ .message("Wrong way!");
+ }
+
+ @Test
+ public void prevent_too_long_messages() {
+ assertThat(new DefaultIssueLocation()
+ .on(inputFile)
+ .message(StringUtils.repeat("a", 4000)).message()).hasSize(4000);
+
+ assertThat(new DefaultIssueLocation()
+ .on(inputFile)
+ .message(StringUtils.repeat("a", 4001)).message()).hasSize(4000);
+ }
+
+ @Test
+ public void prevent_null_character_in_message_text() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Character \\u0000 is not supported in issue message");
+
+ new DefaultIssueLocation()
+ .message("pipo " + '\u0000' + " bimbo");
+ }
+
+ @Test
+ public void prevent_null_character_in_message_text_when_builder_has_been_initialized() {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage(customMatcher("Character \\u0000 is not supported in issue message", ", on component: src/Foo.php"));
+
+ new DefaultIssueLocation()
+ .on(inputFile)
+ .message("pipo " + '\u0000' + " bimbo");
+ }
+
+ private Matcher<String> customMatcher(String startWith, String endWith) {
+ return new TypeSafeMatcher<String>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Invalid message");
+ }
+
+ @Override
+ protected boolean matchesSafely(final String item) {
+ return item.startsWith(startWith) && item.endsWith(endWith);
+ }
+ };
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.File;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.impl.fs.DefaultInputDir;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.issue.DefaultIssue;
+import org.sonar.api.impl.issue.DefaultIssueLocation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultIssueTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private DefaultInputProject project;
+
+ private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
+ .initMetadata("Foo\nBar\n")
+ .build();
+
+ @Before
+ public void prepare() throws IOException {
+ project = new DefaultInputProject(ProjectDefinition.create()
+ .setKey("foo")
+ .setBaseDir(temp.newFolder())
+ .setWorkDir(temp.newFolder()));
+ }
+
+ @Test
+ public void build_file_issue() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultIssue issue = new DefaultIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(1))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .gap(10.0);
+
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
+ assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
+ assertThat(issue.gap()).isEqualTo(10.0);
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
+
+ issue.save();
+
+ verify(storage).store(issue);
+ }
+
+ @Test
+ public void move_directory_issue_to_project_root() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultIssue issue = new DefaultIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(new DefaultInputDir("foo", "src/main").setModuleBaseDir(project.getBaseDir()))
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .overrideSeverity(Severity.BLOCKER);
+
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project);
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
+ assertThat(issue.primaryLocation().textRange()).isNull();
+ assertThat(issue.primaryLocation().message()).isEqualTo("[src/main] Wrong way!");
+ assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
+
+ issue.save();
+
+ verify(storage).store(issue);
+ }
+
+ @Test
+ public void move_submodule_issue_to_project_root() {
+ File subModuleDirectory = new File(project.getBaseDir().toString(), "bar");
+ subModuleDirectory.mkdir();
+
+ ProjectDefinition subModuleDefinition = ProjectDefinition.create()
+ .setKey("foo/bar")
+ .setBaseDir(subModuleDirectory)
+ .setWorkDir(subModuleDirectory);
+ project.definition().addSubProject(subModuleDefinition);
+ DefaultInputModule subModule = new DefaultInputModule(subModuleDefinition);
+
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultIssue issue = new DefaultIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(subModule)
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .overrideSeverity(Severity.BLOCKER);
+
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project);
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
+ assertThat(issue.primaryLocation().textRange()).isNull();
+ assertThat(issue.primaryLocation().message()).isEqualTo("[bar] Wrong way!");
+ assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
+
+ issue.save();
+
+ verify(storage).store(issue);
+ }
+
+ @Test
+ public void build_project_issue() throws IOException {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultInputModule inputModule = new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder()));
+ DefaultIssue issue = new DefaultIssue(project, storage)
+ .at(new DefaultIssueLocation()
+ .on(inputModule)
+ .message("Wrong way!"))
+ .forRule(RuleKey.of("repo", "rule"))
+ .gap(10.0);
+
+ assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputModule);
+ assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
+ assertThat(issue.primaryLocation().textRange()).isNull();
+ assertThat(issue.gap()).isEqualTo(10.0);
+ assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
+
+ issue.save();
+
+ verify(storage).store(issue);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.IOException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultMeasureTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void build_file_measure() {
+ SensorStorage storage = mock(SensorStorage.class);
+ DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
+ .forMetric(CoreMetrics.LINES)
+ .on(new TestInputFileBuilder("foo", "src/Foo.php").build())
+ .withValue(3);
+
+ assertThat(newMeasure.inputComponent()).isEqualTo(new TestInputFileBuilder("foo", "src/Foo.php").build());
+ assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
+ assertThat(newMeasure.value()).isEqualTo(3);
+
+ newMeasure.save();
+
+ verify(storage).store(newMeasure);
+ }
+
+ @Test
+ public void build_project_measure() throws IOException {
+ SensorStorage storage = mock(SensorStorage.class);
+ AbstractProjectOrModule module = new DefaultInputProject(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder()));
+ DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
+ .forMetric(CoreMetrics.LINES)
+ .on(module)
+ .withValue(3);
+
+ assertThat(newMeasure.inputComponent()).isEqualTo(module);
+ assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
+ assertThat(newMeasure.value()).isEqualTo(3);
+
+ newMeasure.save();
+
+ verify(storage).store(newMeasure);
+ }
+
+ @Test
+ public void not_allowed_to_call_on_twice() throws IOException {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("on() already called");
+ new DefaultMeasure<Integer>()
+ .on(new DefaultInputProject(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())))
+ .on(new TestInputFileBuilder("foo", "src/Foo.php").build())
+ .withValue(3)
+ .save();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Test;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.config.MapSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultSensorDescriptorTest {
+
+ @Test
+ public void describe() {
+ DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
+ descriptor
+ .name("Foo")
+ .onlyOnLanguage("java")
+ .onlyOnFileType(InputFile.Type.MAIN)
+ .requireProperty("sonar.foo.reportPath", "sonar.foo.reportPath2")
+ .createIssuesForRuleRepository("squid-java");
+
+ assertThat(descriptor.name()).isEqualTo("Foo");
+ assertThat(descriptor.languages()).containsOnly("java");
+ assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN);
+ MapSettings settings = new MapSettings();
+ settings.setProperty("sonar.foo.reportPath", "foo");
+ assertThat(descriptor.configurationPredicate().test(settings.asConfig())).isFalse();
+ settings.setProperty("sonar.foo.reportPath2", "foo");
+ assertThat(descriptor.configurationPredicate().test(settings.asConfig())).isTrue();
+ assertThat(descriptor.ruleRepositories()).containsOnly("squid-java");
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class DefaultSignificantCodeTest {
+ private SensorStorage sensorStorage = mock(SensorStorage.class);
+ private DefaultSignificantCode underTest = new DefaultSignificantCode(sensorStorage);
+ private InputFile inputFile = TestInputFileBuilder.create("module", "file1.xoo")
+ .setContents("this is\na file\n with some code")
+ .build();
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void should_save_ranges() {
+ underTest.onFile(inputFile)
+ .addRange(inputFile.selectLine(1))
+ .save();
+ verify(sensorStorage).store(underTest);
+ }
+
+ @Test
+ public void fail_if_save_without_file() {
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Call onFile() first");
+ underTest.save();
+ }
+
+ @Test
+ public void fail_if_add_range_to_same_line_twice() {
+ underTest.onFile(inputFile);
+ underTest.addRange(inputFile.selectLine(1));
+
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("Significant code was already reported for line '1'.");
+ underTest.addRange(inputFile.selectLine(1));
+ }
+
+ @Test
+ public void fail_if_range_includes_many_lines() {
+ underTest.onFile(inputFile);
+
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("Ranges of significant code must be located in a single line");
+ underTest.addRange(inputFile.newRange(1, 1, 2, 1));
+ }
+
+ @Test
+ public void fail_if_add_range_before_setting_file() {
+ exception.expect(IllegalStateException.class);
+ exception.expectMessage("addRange() should be called after on()");
+ underTest.addRange(inputFile.selectLine(1));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.util.Map;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class DefaultSymbolTableTest {
+
+ private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java")
+ .setLines(2)
+ .setOriginalLineStartOffsets(new int[] {0, 50})
+ .setOriginalLineEndOffsets(new int[] {49, 100})
+ .setLastValidOffset(101)
+ .build();
+
+ private Map<TextRange, Set<TextRange>> referencesPerSymbol;
+
+ @Rule
+ public ExpectedException throwable = ExpectedException.none();
+
+ @Before
+ public void setUpSampleSymbols() {
+
+ DefaultSymbolTable symbolTableBuilder = new DefaultSymbolTable(mock(SensorStorage.class))
+ .onFile(INPUT_FILE);
+ symbolTableBuilder
+ .newSymbol(0, 10)
+ .newReference(12, 15)
+ .newReference(2, 10, 2, 15);
+
+ symbolTableBuilder.newSymbol(1, 12, 1, 15).newReference(52, 55);
+
+ symbolTableBuilder.save();
+
+ referencesPerSymbol = symbolTableBuilder.getReferencesBySymbol();
+ }
+
+ @Test
+ public void should_register_symbols() {
+ assertThat(referencesPerSymbol).hasSize(2);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.sensor.InMemorySensorStorage;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.data.MapEntry.entry;
+
+public class InMemorySensorStorageTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ InMemorySensorStorage underTest = new InMemorySensorStorage();
+
+ @Test
+ public void test_storeProperty() {
+ assertThat(underTest.contextProperties).isEmpty();
+
+ underTest.storeProperty("foo", "bar");
+ assertThat(underTest.contextProperties).containsOnly(entry("foo", "bar"));
+ }
+
+ @Test
+ public void storeProperty_throws_IAE_if_key_is_null() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Key of context property must not be null");
+
+ underTest.storeProperty(null, "bar");
+ }
+
+ @Test
+ public void storeProperty_throws_IAE_if_value_is_null() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Value of context property must not be null");
+
+ underTest.storeProperty("foo", null);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.sensor;
+
+import java.io.File;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
+import org.sonar.api.batch.rule.NewActiveRule;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.error.AnalysisError;
+import org.sonar.api.batch.sensor.error.NewAnalysisError;
+import org.sonar.api.batch.sensor.highlighting.TypeOfText;
+import org.sonar.api.batch.sensor.issue.NewExternalIssue;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
+import org.sonar.api.config.Settings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.RuleType;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.assertj.core.data.MapEntry.entry;
+
+public class SensorContextTesterTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ private SensorContextTester tester;
+ private File baseDir;
+
+ @Before
+ public void prepare() throws Exception {
+ baseDir = temp.newFolder();
+ tester = SensorContextTester.create(baseDir);
+ }
+
+ @Test
+ public void testSettings() {
+ Settings settings = new MapSettings();
+ settings.setProperty("foo", "bar");
+ tester.setSettings(settings);
+ assertThat(tester.settings().getString("foo")).isEqualTo("bar");
+ }
+
+ @Test
+ public void testActiveRules() {
+ NewActiveRule activeRule = new NewActiveRule.Builder()
+ .setRuleKey(RuleKey.of("foo", "bar"))
+ .build();
+ ActiveRules activeRules = new ActiveRulesBuilder().addRule(activeRule).build();
+ tester.setActiveRules(activeRules);
+ assertThat(tester.activeRules().findAll()).hasSize(1);
+ }
+
+ @Test
+ public void testFs() throws Exception {
+ DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
+ tester.setFileSystem(fs);
+ assertThat(tester.fileSystem().baseDir()).isNotEqualTo(baseDir);
+ }
+
+ @Test
+ public void testIssues() {
+ assertThat(tester.allIssues()).isEmpty();
+ NewIssue newIssue = tester.newIssue();
+ newIssue
+ .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
+ .forRule(RuleKey.of("repo", "rule"))
+ .save();
+ newIssue = tester.newIssue();
+ newIssue
+ .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
+ .forRule(RuleKey.of("repo", "rule"))
+ .save();
+ assertThat(tester.allIssues()).hasSize(2);
+ }
+
+ @Test
+ public void testExternalIssues() {
+ assertThat(tester.allExternalIssues()).isEmpty();
+ NewExternalIssue newExternalIssue = tester.newExternalIssue();
+ newExternalIssue
+ .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
+ .forRule(RuleKey.of("repo", "rule"))
+ .type(RuleType.BUG)
+ .severity(Severity.BLOCKER)
+ .save();
+ newExternalIssue = tester.newExternalIssue();
+ newExternalIssue
+ .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
+ .type(RuleType.BUG)
+ .severity(Severity.BLOCKER)
+ .forRule(RuleKey.of("repo", "rule"))
+ .save();
+ assertThat(tester.allExternalIssues()).hasSize(2);
+ }
+
+ @Test
+ public void testAnalysisErrors() {
+ assertThat(tester.allAnalysisErrors()).isEmpty();
+ NewAnalysisError newAnalysisError = tester.newAnalysisError();
+
+ InputFile file = new TestInputFileBuilder("foo", "src/Foo.java").build();
+ newAnalysisError.onFile(file)
+ .message("error")
+ .at(new DefaultTextPointer(5, 2))
+ .save();
+
+ assertThat(tester.allAnalysisErrors()).hasSize(1);
+ AnalysisError analysisError = tester.allAnalysisErrors().iterator().next();
+
+ assertThat(analysisError.inputFile()).isEqualTo(file);
+ assertThat(analysisError.message()).isEqualTo("error");
+ assertThat(analysisError.location()).isEqualTo(new DefaultTextPointer(5, 2));
+
+ }
+
+ @Test
+ public void testMeasures() throws IOException {
+ assertThat(tester.measures("foo:src/Foo.java")).isEmpty();
+ assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNull();
+ tester.<Integer>newMeasure()
+ .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
+ .forMetric(CoreMetrics.NCLOC)
+ .withValue(2)
+ .save();
+ assertThat(tester.measures("foo:src/Foo.java")).hasSize(1);
+ assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
+ tester.<Integer>newMeasure()
+ .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
+ .forMetric(CoreMetrics.LINES)
+ .withValue(4)
+ .save();
+ assertThat(tester.measures("foo:src/Foo.java")).hasSize(2);
+ assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
+ assertThat(tester.measure("foo:src/Foo.java", "lines")).isNotNull();
+ tester.<Integer>newMeasure()
+ .on(new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())))
+ .forMetric(CoreMetrics.DIRECTORIES)
+ .withValue(4)
+ .save();
+ assertThat(tester.measures("foo")).hasSize(1);
+ assertThat(tester.measure("foo", "directories")).isNotNull();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void duplicateMeasures() {
+ tester.<Integer>newMeasure()
+ .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
+ .forMetric(CoreMetrics.NCLOC)
+ .withValue(2)
+ .save();
+ tester.<Integer>newMeasure()
+ .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
+ .forMetric(CoreMetrics.NCLOC)
+ .withValue(2)
+ .save();
+ }
+
+ @Test
+ public void testHighlighting() {
+ assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).isEmpty();
+ tester.newHighlighting()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
+ .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
+ .highlight(8, 10, TypeOfText.CONSTANT)
+ .highlight(9, 10, TypeOfText.COMMENT)
+ .save();
+ assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).containsExactly(TypeOfText.ANNOTATION);
+ assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 9)).containsExactly(TypeOfText.CONSTANT, TypeOfText.COMMENT);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateHighlighting() {
+ tester.newHighlighting()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
+ .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
+ .save();
+ tester.newHighlighting()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
+ .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
+ .save();
+ }
+
+ @Test
+ public void testSymbolReferences() {
+ assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
+
+ NewSymbolTable symbolTable = tester.newSymbolTable()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
+ symbolTable
+ .newSymbol(1, 8, 1, 10);
+
+ symbolTable
+ .newSymbol(1, 1, 1, 5)
+ .newReference(6, 9)
+ .newReference(1, 10, 1, 13);
+
+ symbolTable.save();
+
+ assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
+ assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 8)).isEmpty();
+ assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 3)).extracting("start.line", "start.lineOffset", "end.line", "end.lineOffset").containsExactly(tuple(1, 6, 1, 9),
+ tuple(1, 10, 1, 13));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateSymbolReferences() {
+ NewSymbolTable symbolTable = tester.newSymbolTable()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
+ symbolTable
+ .newSymbol(1, 8, 1, 10);
+
+ symbolTable.save();
+
+ symbolTable = tester.newSymbolTable()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
+ symbolTable
+ .newSymbol(1, 8, 1, 10);
+
+ symbolTable.save();
+ }
+
+ @Test
+ public void testCoverageAtLineZero() {
+ assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
+ assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
+
+ exception.expect(IllegalStateException.class);
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
+ .lineHits(0, 3);
+ }
+
+ @Test
+ public void testCoverageAtLineOutOfRange() {
+ assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
+ assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
+ exception.expect(IllegalStateException.class);
+
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
+ .lineHits(4, 3);
+ }
+
+ @Test
+ public void testLineHits() {
+ assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
+ assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
+ .lineHits(1, 2)
+ .lineHits(2, 3)
+ .save();
+ assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(2);
+ assertThat(tester.lineHits("foo:src/Foo.java", 2)).isEqualTo(3);
+ }
+
+ public void multipleCoverage() {
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
+ .lineHits(1, 2)
+ .conditions(3, 4, 2)
+ .save();
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
+ .lineHits(1, 2)
+ .conditions(3, 4, 3)
+ .save();
+ assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(4);
+ assertThat(tester.conditions("foo:src/Foo.java", 3)).isEqualTo(4);
+ assertThat(tester.coveredConditions("foo:src/Foo.java", 3)).isEqualTo(3);
+ }
+
+ @Test
+ public void testConditions() {
+ assertThat(tester.conditions("foo:src/Foo.java", 1)).isNull();
+ assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isNull();
+ tester.newCoverage()
+ .onFile(new TestInputFileBuilder("foo", "src/Foo.java")
+ .initMetadata("annot dsf fds foo bar\nasd\nasdas\nasdfas")
+ .build())
+ .conditions(1, 4, 2)
+ .save();
+ assertThat(tester.conditions("foo:src/Foo.java", 1)).isEqualTo(4);
+ assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isEqualTo(2);
+ }
+
+ @Test
+ public void testCpdTokens() {
+ assertThat(tester.cpdTokens("foo:src/Foo.java")).isNull();
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
+ .initMetadata("public class Foo {\n\n}")
+ .build();
+ tester.newCpdTokens()
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(0, 6), "public")
+ .addToken(inputFile.newRange(7, 12), "class")
+ .addToken(inputFile.newRange(13, 16), "$IDENTIFIER")
+ .addToken(inputFile.newRange(17, 18), "{")
+ .addToken(inputFile.newRange(3, 0, 3, 1), "}")
+ .save();
+ assertThat(tester.cpdTokens("foo:src/Foo.java")).extracting("value", "startLine", "startUnit", "endUnit")
+ .containsExactly(
+ tuple("publicclass$IDENTIFIER{", 1, 1, 4),
+ tuple("}", 3, 5, 5));
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateCpdTokens() {
+ DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
+ .initMetadata("public class Foo {\n\n}")
+ .build();
+ tester.newCpdTokens()
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(0, 6), "public")
+ .save();
+
+ tester.newCpdTokens()
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(0, 6), "public")
+ .save();
+ }
+
+ @Test
+ public void testCancellation() {
+ assertThat(tester.isCancelled()).isFalse();
+ tester.setCancelled(true);
+ assertThat(tester.isCancelled()).isTrue();
+ }
+
+ @Test
+ public void testContextProperties() {
+ assertThat(tester.getContextProperties()).isEmpty();
+
+ tester.addContextProperty("foo", "bar");
+ assertThat(tester.getContextProperties()).containsOnly(entry("foo", "bar"));
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.server;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleScope;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultNewRuleTest {
+ @Rule
+ public ExpectedException exception = ExpectedException.none();
+
+ private DefaultNewRule rule = new DefaultNewRule("plugin", "repo", "key");
+
+ @Test
+ public void testSimpleSetGet() {
+ assertThat(rule.pluginKey()).isEqualTo("plugin");
+ assertThat(rule.repoKey()).isEqualTo("repo");
+ assertThat(rule.key()).isEqualTo("key");
+
+ rule.setScope(RuleScope.MAIN);
+ assertThat(rule.scope()).isEqualTo(RuleScope.MAIN);
+
+ rule.setName(" name ");
+ assertThat(rule.name()).isEqualTo("name");
+
+ rule.setHtmlDescription(" html ");
+ assertThat(rule.htmlDescription()).isEqualTo("html");
+
+ rule.setTemplate(true);
+ assertThat(rule.template()).isTrue();
+
+ rule.setActivatedByDefault(true);
+ assertThat(rule.activatedByDefault()).isTrue();
+
+ RulesDefinition.NewParam param1 = rule.createParam("param1");
+ assertThat(rule.param("param1")).isEqualTo(param1);
+ assertThat(rule.params()).containsOnly(param1);
+
+ rule.setTags("tag1", "tag2");
+ rule.addTags("tag3");
+ assertThat(rule.tags()).containsExactly("tag1", "tag2", "tag3");
+
+ rule.setEffortToFixDescription("effort");
+ assertThat(rule.gapDescription()).isEqualTo("effort");
+
+ rule.setGapDescription("gap");
+ assertThat(rule.gapDescription()).isEqualTo("gap");
+
+ rule.setInternalKey("internal");
+ assertThat(rule.internalKey()).isEqualTo("internal");
+
+ rule.addDeprecatedRuleKey("deprecatedrepo", "deprecatedkey");
+ assertThat(rule.deprecatedRuleKeys()).containsOnly(RuleKey.of("deprecatedrepo", "deprecatedkey"));
+ }
+
+ @Test
+ public void fail_if_severity_is_invalid() {
+ exception.expect(IllegalArgumentException.class);
+ rule.setSeverity("invalid");
+ }
+
+ @Test
+ public void fail_setting_markdown_if_html_is_set() {
+ exception.expect(IllegalStateException.class);
+ rule.setHtmlDescription("html");
+ rule.setMarkdownDescription("markdown");
+ }
+
+ @Test
+ public void fail_if_set_status_to_removed() {
+ exception.expect(IllegalArgumentException.class);
+ rule.setStatus(RuleStatus.REMOVED);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class AlwaysIncreasingSystem2Test {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void default_constructor_makes_now_start_with_random_number_and_increase_returned_value_by_100_with_each_call() {
+ AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2();
+ verifyValuesReturnedByNow(underTest, null, 100);
+ }
+
+ @Test
+ public void constructor_with_increment_makes_now_start_with_random_number_and_increase_returned_value_by_specified_value_with_each_call() {
+ AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(663);
+
+ verifyValuesReturnedByNow(underTest, null, 663);
+ }
+
+ @Test
+ public void constructor_with_initial_value_and_increment_makes_now_start_with_specified_value_and_increase_returned_value_by_specified_value_with_each_call() {
+ AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(777777L, 96);
+
+ verifyValuesReturnedByNow(underTest, 777777L, 96);
+ }
+
+ @Test
+ public void constructor_with_initial_value_and_increment_throws_IAE_if_initial_value_is_less_than_0() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Initial value must be >= 0");
+
+ new AlwaysIncreasingSystem2(-1, 100);
+ }
+
+ @Test
+ public void constructor_with_initial_value_and_increment_accepts_initial_value_0() {
+ AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(0, 100);
+
+ verifyValuesReturnedByNow(underTest, 0L, 100);
+ }
+
+ @Test
+ public void constructor_with_initial_value_and_increment_throws_IAE_if_increment_is_0() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("increment must be > 0");
+
+ new AlwaysIncreasingSystem2(10, 0);
+ }
+
+ @Test
+ public void constructor_with_initial_value_and_increment_throws_IAE_if_increment_is_less_than_0() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("increment must be > 0");
+
+ new AlwaysIncreasingSystem2(10, -66);
+ }
+
+ @Test
+ public void constructor_with_increment_throws_IAE_if_increment_is_0() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("increment must be > 0");
+
+ new AlwaysIncreasingSystem2(0);
+ }
+
+ @Test
+ public void constructor_with_increment_throws_IAE_if_increment_is_less_than_0() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("increment must be > 0");
+
+ new AlwaysIncreasingSystem2(-20);
+ }
+
+ private void verifyValuesReturnedByNow(AlwaysIncreasingSystem2 underTest, @Nullable Long initialValue, int increment) {
+ long previousValue = -1;
+ for (int i = 0; i < 333; i++) {
+ if (previousValue == -1) {
+ long now = underTest.now();
+ if (initialValue != null) {
+ assertThat(now).isEqualTo(initialValue);
+ } else {
+ assertThat(now).isGreaterThan(0);
+ }
+ previousValue = now;
+ } else {
+ long now = underTest.now();
+ assertThat(now).isEqualTo(previousValue + increment);
+ previousValue = now;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import java.io.File;
+import org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.server.util.TempFolderCleaner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefaultTempFolderTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Test
+ public void createTempFolderAndFile() throws Exception {
+ File rootTempFolder = temp.newFolder();
+ DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
+ File dir = underTest.newDir();
+ assertThat(dir).exists().isDirectory();
+ File file = underTest.newFile();
+ assertThat(file).exists().isFile();
+
+ new TempFolderCleaner(underTest).stop();
+ assertThat(rootTempFolder).doesNotExist();
+ }
+
+ @Test
+ public void createTempFolderWithName() throws Exception {
+ File rootTempFolder = temp.newFolder();
+ DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
+ File dir = underTest.newDir("sample");
+ assertThat(dir).exists().isDirectory();
+ assertThat(new File(rootTempFolder, "sample")).isEqualTo(dir);
+
+ new TempFolderCleaner(underTest).stop();
+ assertThat(rootTempFolder).doesNotExist();
+ }
+
+ @Test
+ public void newDir_throws_ISE_if_name_is_not_valid() throws Exception {
+ File rootTempFolder = temp.newFolder();
+ DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
+ String tooLong = "tooooolong";
+ for (int i = 0; i < 50; i++) {
+ tooLong += "tooooolong";
+ }
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Failed to create temp directory");
+
+ underTest.newDir(tooLong);
+ }
+
+ @Test
+ public void newFile_throws_ISE_if_name_is_not_valid() throws Exception {
+ File rootTempFolder = temp.newFolder();
+ DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
+ String tooLong = "tooooolong";
+ for (int i = 0; i < 50; i++) {
+ tooLong += "tooooolong";
+ }
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Failed to create temp file");
+
+ underTest.newFile(tooLong, ".txt");
+ }
+
+ @Test
+ public void clean_deletes_non_empty_directory() throws Exception {
+ File dir = temp.newFolder();
+ FileUtils.touch(new File(dir, "foo.txt"));
+
+ DefaultTempFolder underTest = new DefaultTempFolder(dir);
+ underTest.clean();
+
+ assertThat(dir).doesNotExist();
+ }
+
+ @Test
+ public void clean_does_not_fail_if_directory_has_already_been_deleted() throws Exception {
+ File dir = temp.newFolder();
+
+ DefaultTempFolder underTest = new DefaultTempFolder(dir);
+ underTest.clean();
+ assertThat(dir).doesNotExist();
+
+ // second call does not fail, nor log ERROR logs
+ underTest.clean();
+
+ assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class JUnitTempFolderTest {
+
+ @Test
+ public void apply() throws Throwable {
+ JUnitTempFolder temp = new JUnitTempFolder();
+ temp.before();
+ File dir1 = temp.newDir();
+ assertThat(dir1).isDirectory().exists();
+
+ File dir2 = temp.newDir("foo");
+ assertThat(dir2).isDirectory().exists();
+
+ File file1 = temp.newFile();
+ assertThat(file1).isFile().exists();
+
+ File file2 = temp.newFile("foo", "txt");
+ assertThat(file2).isFile().exists();
+
+ temp.after();
+ assertThat(dir1).doesNotExist();
+ assertThat(dir2).doesNotExist();
+ assertThat(file1).doesNotExist();
+ assertThat(file2).doesNotExist();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ScannerUtilsTest {
+ @Test
+ public void test_pluralize() {
+ assertThat(ScannerUtils.pluralize("string", 0)).isEqualTo("strings");
+ assertThat(ScannerUtils.pluralize("string", 1)).isEqualTo("string");
+ assertThat(ScannerUtils.pluralize("string", 2)).isEqualTo("strings");
+ }
+
+ @Test
+ public void cleanKeyForFilename() {
+ assertThat(ScannerUtils.cleanKeyForFilename("project 1")).isEqualTo("project1");
+ assertThat(ScannerUtils.cleanKeyForFilename("project:1")).isEqualTo("project_1");
+ }
+
+ @Test
+ public void describe() {
+ assertThat(ScannerUtils.describe(new Object())).isEqualTo("java.lang.Object");
+ assertThat(ScannerUtils.describe(new TestClass())).isEqualTo("overridden");
+ }
+
+ class TestClass {
+ @Override
+ public String toString() {
+ return "overridden";
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.utils;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class WorkDurationTest {
+
+ static final int HOURS_IN_DAY = 8;
+
+ static final Long ONE_MINUTE = 1L;
+ static final Long ONE_HOUR_IN_MINUTES = ONE_MINUTE * 60;
+ static final Long ONE_DAY_IN_MINUTES = ONE_HOUR_IN_MINUTES * HOURS_IN_DAY;
+
+ @Test
+ public void create_from_days_hours_minutes() {
+ WorkDuration workDuration = WorkDuration.create(1, 1, 1, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(1);
+ assertThat(workDuration.hours()).isEqualTo(1);
+ assertThat(workDuration.minutes()).isEqualTo(1);
+ assertThat(workDuration.toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES + ONE_HOUR_IN_MINUTES + ONE_MINUTE);
+ assertThat(workDuration.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+ }
+
+ @Test
+ public void create_from_value_and_unit() {
+ WorkDuration result = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY);
+ assertThat(result.days()).isEqualTo(1);
+ assertThat(result.hours()).isEqualTo(0);
+ assertThat(result.minutes()).isEqualTo(0);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+ assertThat(result.toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES);
+
+ assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES);
+ assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_HOUR_IN_MINUTES);
+ assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_MINUTE);
+ }
+
+ @Test
+ public void create_from_minutes() {
+ WorkDuration workDuration = WorkDuration.createFromMinutes(ONE_MINUTE, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(0);
+ assertThat(workDuration.hours()).isEqualTo(0);
+ assertThat(workDuration.minutes()).isEqualTo(1);
+
+ workDuration = WorkDuration.createFromMinutes(ONE_HOUR_IN_MINUTES, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(0);
+ assertThat(workDuration.hours()).isEqualTo(1);
+ assertThat(workDuration.minutes()).isEqualTo(0);
+
+ workDuration = WorkDuration.createFromMinutes(ONE_DAY_IN_MINUTES, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(1);
+ assertThat(workDuration.hours()).isEqualTo(0);
+ assertThat(workDuration.minutes()).isEqualTo(0);
+ }
+
+ @Test
+ public void create_from_working_long() {
+ // 1 minute
+ WorkDuration workDuration = WorkDuration.createFromLong(1L, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(0);
+ assertThat(workDuration.hours()).isEqualTo(0);
+ assertThat(workDuration.minutes()).isEqualTo(1);
+
+ // 1 hour
+ workDuration = WorkDuration.createFromLong(100L, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(0);
+ assertThat(workDuration.hours()).isEqualTo(1);
+ assertThat(workDuration.minutes()).isEqualTo(0);
+
+ // 1 day
+ workDuration = WorkDuration.createFromLong(10000L, HOURS_IN_DAY);
+ assertThat(workDuration.days()).isEqualTo(1);
+ assertThat(workDuration.hours()).isEqualTo(0);
+ assertThat(workDuration.minutes()).isEqualTo(0);
+ }
+
+ @Test
+ public void convert_to_seconds() {
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_MINUTE);
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_HOUR_IN_MINUTES);
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_DAY_IN_MINUTES);
+ }
+
+ @Test
+ public void convert_to_working_days() {
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d / 60d / 8d);
+ assertThat(WorkDuration.createFromValueAndUnit(240, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toWorkingDays()).isEqualTo(0.5);
+ assertThat(WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(0.5);
+ assertThat(WorkDuration.createFromValueAndUnit(8, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(1d);
+ assertThat(WorkDuration.createFromValueAndUnit(16, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d);
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d);
+ }
+
+ @Test
+ public void convert_to_working_long() {
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toLong()).isEqualTo(2l);
+ assertThat(WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(400l);
+ assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(10200l);
+ assertThat(WorkDuration.createFromValueAndUnit(8, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(10000l);
+ assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toLong()).isEqualTo(20000l);
+ }
+
+ @Test
+ public void add() {
+ // 4h + 5h = 1d 1h
+ WorkDuration result = WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).add(WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY));
+ assertThat(result.days()).isEqualTo(1);
+ assertThat(result.hours()).isEqualTo(1);
+ assertThat(result.minutes()).isEqualTo(0);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+
+ // 40 m + 30m = 1h 10m
+ result = WorkDuration.createFromValueAndUnit(40, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY));
+ assertThat(result.days()).isEqualTo(0);
+ assertThat(result.hours()).isEqualTo(1);
+ assertThat(result.minutes()).isEqualTo(10);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+
+ // 10 m + 20m = 30m
+ assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(
+ WorkDuration.createFromValueAndUnit(20, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)
+ ).minutes()).isEqualTo(30);
+
+ assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(null).minutes()).isEqualTo(10);
+ }
+
+ @Test
+ public void subtract() {
+ // 1d 1h - 5h = 4h
+ WorkDuration result = WorkDuration.create(1, 1, 0, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY));
+ assertThat(result.days()).isEqualTo(0);
+ assertThat(result.hours()).isEqualTo(4);
+ assertThat(result.minutes()).isEqualTo(0);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+
+ // 1h 10m - 30m = 40m
+ result = WorkDuration.create(0, 1, 10, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY));
+ assertThat(result.days()).isEqualTo(0);
+ assertThat(result.hours()).isEqualTo(0);
+ assertThat(result.minutes()).isEqualTo(40);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+
+ // 30m - 20m = 10m
+ assertThat(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(20, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY))
+ .minutes()).isEqualTo(10);
+
+ assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).subtract(null).minutes()).isEqualTo(10);
+ }
+
+ @Test
+ public void multiply() {
+ // 5h * 2 = 1d 2h
+ WorkDuration result = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).multiply(2);
+ assertThat(result.days()).isEqualTo(1);
+ assertThat(result.hours()).isEqualTo(2);
+ assertThat(result.minutes()).isEqualTo(0);
+ assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
+ }
+
+ @Test
+ public void test_equals_and_hashcode() throws Exception {
+ WorkDuration duration = WorkDuration.createFromLong(28800, HOURS_IN_DAY);
+ WorkDuration durationWithSameValue = WorkDuration.createFromLong(28800, HOURS_IN_DAY);
+ WorkDuration durationWithDifferentValue = WorkDuration.createFromLong(14400, HOURS_IN_DAY);
+
+ assertThat(duration).isEqualTo(duration);
+ assertThat(durationWithSameValue).isEqualTo(duration);
+ assertThat(durationWithDifferentValue).isNotEqualTo(duration);
+ assertThat(duration).isNotEqualTo(null);
+
+ assertThat(duration.hashCode()).isEqualTo(duration.hashCode());
+ assertThat(durationWithSameValue.hashCode()).isEqualTo(duration.hashCode());
+ assertThat(durationWithDifferentValue.hashCode()).isNotEqualTo(duration.hashCode());
+ }
+
+ @Test
+ public void test_toString() throws Exception {
+ assertThat(WorkDuration.createFromLong(28800, HOURS_IN_DAY).toString()).isNotNull();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.impl.ws;
+
+import java.io.InputStream;
+import org.junit.Test;
+import org.sonar.api.server.ws.Request;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.mock;
+
+public class SimpleGetRequestTest {
+
+ org.sonar.api.impl.ws.SimpleGetRequest underTest = new SimpleGetRequest();
+
+ @Test
+ public void method() {
+ assertThat(underTest.method()).isEqualTo("GET");
+
+ underTest.setParam("foo", "bar");
+ assertThat(underTest.param("foo")).isEqualTo("bar");
+ assertThat(underTest.param("unknown")).isNull();
+ }
+
+ @Test
+ public void has_param() {
+ assertThat(underTest.method()).isEqualTo("GET");
+
+ underTest.setParam("foo", "bar");
+ assertThat(underTest.hasParam("foo")).isTrue();
+ assertThat(underTest.hasParam("unknown")).isFalse();
+ }
+
+ @Test
+ public void get_part() {
+ InputStream inputStream = mock(InputStream.class);
+ underTest.setPart("key", inputStream, "filename");
+
+ Request.Part part = underTest.paramAsPart("key");
+ assertThat(part.getInputStream()).isEqualTo(inputStream);
+ assertThat(part.getFileName()).isEqualTo("filename");
+
+ assertThat(underTest.paramAsPart("unknown")).isNull();
+ }
+
+ @Test
+ public void getMediaType() {
+ underTest.setMediaType("JSON");
+
+ assertThat(underTest.getMediaType()).isEqualTo("JSON");
+ }
+
+ @Test
+ public void multiParam_with_one_element() {
+ underTest.setParam("foo", "bar");
+
+ assertThat(underTest.multiParam("foo")).containsExactly("bar");
+ }
+
+ @Test
+ public void multiParam_without_any_element() {
+ assertThat(underTest.multiParam("42")).isEmpty();
+ }
+
+ @Test
+ public void getParams() {
+ underTest
+ .setParam("foo", "bar")
+ .setParam("fee", "beer");
+
+ assertThat(underTest.getParams()).containsOnly(
+ entry("foo", new String[] {"bar"}),
+ entry("fee", new String[] {"beer"}));
+ }
+
+ @Test
+ public void header_returns_empty_if_header_is_not_present() {
+ assertThat(underTest.header("foo")).isEmpty();
+ }
+
+ @Test
+ public void header_returns_value_of_header_if_present() {
+ underTest.setHeader("foo", "bar");
+ assertThat(underTest.header("foo")).hasValue("bar");
+ }
+
+ @Test
+ public void header_returns_empty_string_value_if_header_is_present_without_value() {
+ underTest.setHeader("foo", "");
+ assertThat(underTest.header("foo")).hasValue("");
+ }
+}
testCompile 'com.tngtech.java:junit-dataprovider'
testCompile 'org.assertj:assertj-core'
testCompile 'org.mockito:mockito-core'
- testCompile project(':sonar-scanner-engine')
- testCompile project(':server:sonar-server')
+ testCompile project(':sonar-plugin-api-impl')
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.batch.fs.internal;
-
-import java.util.Arrays;
-
-import javax.annotation.concurrent.Immutable;
-
-@Immutable
-public class Metadata {
- private final int lines;
- private final int nonBlankLines;
- private final String hash;
- private final int[] originalLineStartOffsets;
- private final int[] originalLineEndOffsets;
- private final int lastValidOffset;
-
- public Metadata(int lines, int nonBlankLines, String hash, int[] originalLineStartOffsets, int[] originalLineEndOffsets, int lastValidOffset) {
- this.lines = lines;
- this.nonBlankLines = nonBlankLines;
- this.hash = hash;
- this.originalLineStartOffsets = Arrays.copyOf(originalLineStartOffsets, originalLineStartOffsets.length);
- this.originalLineEndOffsets = Arrays.copyOf(originalLineEndOffsets, originalLineEndOffsets.length);
- this.lastValidOffset = lastValidOffset;
- }
-
- public int lines() {
- return lines;
- }
-
- public int nonBlankLines() {
- return nonBlankLines;
- }
-
- public String hash() {
- return hash;
- }
-
- public int[] originalLineStartOffsets() {
- return originalLineStartOffsets;
- }
-
- public int[] originalLineEndOffsets() {
- return originalLineEndOffsets;
- }
-
- public int lastValidOffset() {
- return lastValidOffset;
- }
-
- public boolean isEmpty() {
- return lastValidOffset == 0;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.batch.fs.internal;
-
-import java.nio.file.Path;
-import javax.annotation.concurrent.ThreadSafe;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.utils.PathUtils;
-import org.sonar.api.utils.WildcardPattern;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-@ThreadSafe
-public abstract class PathPattern {
-
- private static final Logger LOG = Loggers.get(PathPattern.class);
-
- /**
- * @deprecated since 6.6
- */
- @Deprecated
- private static final String ABSOLUTE_PATH_PATTERN_PREFIX = "file:";
- final WildcardPattern pattern;
-
- PathPattern(String pattern) {
- this.pattern = WildcardPattern.create(pattern);
- }
-
- public abstract boolean match(Path absolutePath, Path relativePath);
-
- public abstract boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension);
-
- public static PathPattern create(String s) {
- String trimmed = StringUtils.trim(s);
- if (StringUtils.startsWithIgnoreCase(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX)) {
- LOG.warn("Using absolute path pattern is deprecated. Please use relative path instead of '" + trimmed + "'");
- return new AbsolutePathPattern(StringUtils.substring(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX.length()));
- }
- return new RelativePathPattern(trimmed);
- }
-
- public static PathPattern[] create(String[] s) {
- PathPattern[] result = new PathPattern[s.length];
- for (int i = 0; i < s.length; i++) {
- result[i] = create(s[i]);
- }
- return result;
- }
-
- /**
- * @deprecated since 6.6
- */
- @Deprecated
- private static class AbsolutePathPattern extends PathPattern {
- private AbsolutePathPattern(String pattern) {
- super(pattern);
- }
-
- @Override
- public boolean match(Path absolutePath, Path relativePath) {
- return match(absolutePath, relativePath, true);
- }
-
- @Override
- public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
- String path = PathUtils.sanitize(absolutePath.toString());
- if (!caseSensitiveFileExtension) {
- String extension = sanitizeExtension(FilenameUtils.getExtension(path));
- if (StringUtils.isNotBlank(extension)) {
- path = StringUtils.removeEndIgnoreCase(path, extension);
- path = path + extension;
- }
- }
- return pattern.match(path);
- }
-
- @Override
- public String toString() {
- return ABSOLUTE_PATH_PATTERN_PREFIX + pattern.toString();
- }
- }
-
- /**
- * Path relative to module basedir
- */
- private static class RelativePathPattern extends PathPattern {
- private RelativePathPattern(String pattern) {
- super(pattern);
- }
-
- @Override
- public boolean match(Path absolutePath, Path relativePath) {
- return match(absolutePath, relativePath, true);
- }
-
- @Override
- public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
- String path = PathUtils.sanitize(relativePath.toString());
- if (!caseSensitiveFileExtension) {
- String extension = sanitizeExtension(FilenameUtils.getExtension(path));
- if (StringUtils.isNotBlank(extension)) {
- path = StringUtils.removeEndIgnoreCase(path, extension);
- path = path + extension;
- }
- }
- return path != null && pattern.match(path);
- }
-
- @Override
- public String toString() {
- return pattern.toString();
- }
- }
-
- static String sanitizeExtension(String suffix) {
- return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.batch.fs.internal;
-
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * A shared, mutable object in the project container.
- * It's used during the execution of sensors to decide whether
- * sensors should be executed once for the entire project, or per-module.
- * It is also injected into each InputFile to change the behavior of {@link InputFile#relativePath()}
- */
-public class SensorStrategy {
-
- private boolean global = true;
-
- public boolean isGlobal() {
- return global;
- }
-
- public void setGlobal(boolean global) {
- this.global = global;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.batch.fs.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.rule.RuleKey;
+
+public class LoadedActiveRule {
+ private RuleKey ruleKey;
+ private String severity;
+ private String name;
+ private String language;
+ private Map<String, String> params;
+ private long createdAt;
+ private long updatedAt;
+ private String templateRuleKey;
+ private String internalKey;
+
+ public RuleKey getRuleKey() {
+ return ruleKey;
+ }
+
+ public void setRuleKey(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSeverity() {
+ return severity;
+ }
+
+ public void setSeverity(String severity) {
+ this.severity = severity;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public Map<String, String> getParams() {
+ return params;
+ }
+
+ public void setParams(Map<String, String> params) {
+ this.params = params;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public long getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(long updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ @CheckForNull
+ public String getTemplateRuleKey() {
+ return templateRuleKey;
+ }
+
+ public void setTemplateRuleKey(@Nullable String templateRuleKey) {
+ this.templateRuleKey = templateRuleKey;
+ }
+
+ public String getInternalKey() {
+ return internalKey;
+ }
+
+ public void setInternalKey(String internalKey) {
+ this.internalKey = internalKey;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+
+/**
+ * @since 4.2
+ */
+@Immutable
+public class NewActiveRule {
+ final RuleKey ruleKey;
+ final String name;
+ final String severity;
+ final Map<String, String> params;
+ final long createdAt;
+ final long updatedAt;
+ final String internalKey;
+ final String language;
+ final String templateRuleKey;
+ final String qProfileKey;
+
+ NewActiveRule(Builder builder) {
+ this.ruleKey = builder.ruleKey;
+ this.name = builder.name;
+ this.severity = builder.severity;
+ this.params = builder.params;
+ this.createdAt = builder.createdAt;
+ this.updatedAt = builder.updatedAt;
+ this.internalKey = builder.internalKey;
+ this.language = builder.language;
+ this.templateRuleKey = builder.templateRuleKey;
+ this.qProfileKey = builder.qProfileKey;
+ }
+
+ public RuleKey ruleKey() {
+ return this.ruleKey;
+ }
+
+ public static class Builder {
+ private RuleKey ruleKey;
+ private String name;
+ private String severity = Severity.defaultSeverity();
+ private Map<String, String> params = new HashMap<>();
+ private long createdAt;
+ private long updatedAt;
+ private String internalKey;
+ private String language;
+ private String templateRuleKey;
+ private String qProfileKey;
+
+ public Builder setRuleKey(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ public Builder setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder setSeverity(@Nullable String severity) {
+ this.severity = StringUtils.defaultIfBlank(severity, Severity.defaultSeverity());
+ return this;
+ }
+
+ public Builder setParam(String key, @Nullable String value) {
+ // possible improvement : check that the param key exists in rule definition
+ if (value == null) {
+ params.remove(key);
+ } else {
+ params.put(key, value);
+ }
+ return this;
+ }
+
+ public Builder setCreatedAt(long createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ public Builder setUpdatedAt(long updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ public Builder setInternalKey(@Nullable String internalKey) {
+ this.internalKey = internalKey;
+ return this;
+ }
+
+ public Builder setLanguage(@Nullable String language) {
+ this.language = language;
+ return this;
+ }
+
+ public Builder setTemplateRuleKey(@Nullable String templateRuleKey) {
+ this.templateRuleKey = templateRuleKey;
+ return this;
+ }
+
+ public Builder setQProfileKey(String qProfileKey) {
+ this.qProfileKey = qProfileKey;
+ return this;
+ }
+
+ public NewActiveRule build() {
+ return new NewActiveRule(this);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.rule.Severity;
+
+public class NewRule {
+
+ private static final String DEFAULT_SEVERITY = Severity.defaultSeverity();
+
+ final RuleKey key;
+ Integer id;
+ String name;
+ String description;
+ String severity = DEFAULT_SEVERITY;
+ String type;
+ String internalKey;
+ RuleStatus status = RuleStatus.defaultStatus();
+ Map<String, NewRuleParam> params = new HashMap<>();
+
+ public NewRule(RuleKey key) {
+ this.key = key;
+ }
+
+ public NewRule setId(@Nullable Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ public NewRule setDescription(@Nullable String description) {
+ this.description = description;
+ return this;
+ }
+
+ public NewRule setName(@Nullable String s) {
+ this.name = s;
+ return this;
+ }
+
+ public NewRule setSeverity(@Nullable String severity) {
+ this.severity = StringUtils.defaultIfBlank(severity, DEFAULT_SEVERITY);
+ return this;
+ }
+
+ public NewRule setType(@Nullable String type) {
+ this.type = type;
+ return this;
+ }
+
+ public NewRule setStatus(@Nullable RuleStatus s) {
+ this.status = (RuleStatus) ObjectUtils.defaultIfNull(s, RuleStatus.defaultStatus());
+ return this;
+ }
+
+ public NewRule setInternalKey(@Nullable String s) {
+ this.internalKey = s;
+ return this;
+ }
+
+ public NewRuleParam addParam(String paramKey) {
+ if (params.containsKey(paramKey)) {
+ throw new IllegalStateException(String.format("Parameter '%s' already exists on rule '%s'", paramKey, key));
+ }
+ NewRuleParam param = new NewRuleParam(paramKey);
+ params.put(paramKey, param);
+ return param;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import javax.annotation.Nullable;
+
+public class NewRuleParam {
+ final String key;
+ String description;
+
+ NewRuleParam(String key) {
+ this.key = key;
+ }
+
+ public NewRuleParam setDescription(@Nullable String s) {
+ description = s;
+ return this;
+ }
+}
import java.util.Optional;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.server.ServerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;
* </pre>
*
* <p>
- * For testing, and only for testing, the in-memory implementation {@link MapSettings} can be used.
+ * For testing, and only for testing, the in-memory implementation MapSettings can be used.
* <pre>
* {@literal @}Test
* public void my_test() {
* }
* </pre>
*
- * @see MapSettings
* @see PropertyDefinition
* @since 6.5
*/
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.config.internal;
-
-import java.util.Optional;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.Configuration;
-
-/**
- * Used to help migration from {@link Settings} to {@link Configuration}
- */
-public class ConfigurationBridge implements Configuration {
-
- private final Settings settings;
-
- public ConfigurationBridge(Settings settings) {
- this.settings = settings;
- }
-
- @Override
- public Optional<String> get(String key) {
- return Optional.ofNullable(settings.getString(key));
- }
-
- @Override
- public boolean hasKey(String key) {
- return settings.hasKey(key);
- }
-
- @Override
- public String[] getStringArray(String key) {
- return settings.getStringArray(key);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.config.internal;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.config.Encryption;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-
-import static java.util.Collections.unmodifiableMap;
-import static java.util.Objects.requireNonNull;
-
-/**
- * In-memory map-based implementation of {@link Settings}. It must be used
- * <b>only for unit tests</b>. This is not the implementation
- * deployed at runtime, so non-test code must never cast
- * {@link Settings} to {@link MapSettings}.
- *
- * @since 6.1
- */
-public class MapSettings extends Settings {
-
- private final Map<String, String> props = new HashMap<>();
- private final ConfigurationBridge configurationBridge;
-
- public MapSettings() {
- this(new PropertyDefinitions());
- }
-
- public MapSettings(PropertyDefinitions definitions) {
- super(definitions, new Encryption(null));
- configurationBridge = new ConfigurationBridge(this);
- }
-
- @Override
- protected Optional<String> get(String key) {
- return Optional.ofNullable(props.get(key));
- }
-
- @Override
- protected void set(String key, String value) {
- props.put(
- requireNonNull(key, "key can't be null"),
- requireNonNull(value, "value can't be null").trim());
- }
-
- @Override
- protected void remove(String key) {
- props.remove(key);
- }
-
- @Override
- public Map<String, String> getProperties() {
- return unmodifiableMap(props);
- }
-
- /**
- * Delete all properties
- */
- public MapSettings clear() {
- props.clear();
- return this;
- }
-
- @Override
- public MapSettings setProperty(String key, String value) {
- return (MapSettings) super.setProperty(key, value);
- }
-
- @Override
- public MapSettings setProperty(String key, Integer value) {
- return (MapSettings) super.setProperty(key, value);
- }
-
- @Override
- public MapSettings setProperty(String key, Boolean value) {
- return (MapSettings) super.setProperty(key, value);
- }
-
- @Override
- public MapSettings setProperty(String key, Long value) {
- return (MapSettings) super.setProperty(key, value);
- }
-
- /**
- * @return a {@link Configuration} proxy on top of this existing {@link Settings} implementation. Changes are reflected in the {@link Configuration} object.
- * @since 6.5
- */
- public Configuration asConfig() {
- return configurationBridge;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.config.internal;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Function;
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVParser;
-import org.apache.commons.csv.CSVRecord;
-import org.apache.commons.lang.ArrayUtils;
-
-public class MultivalueProperty {
- private MultivalueProperty() {
- // prevents instantiation
- }
-
- public static String[] parseAsCsv(String key, String value) {
- return parseAsCsv(key, value, Function.identity());
- }
-
- public static String[] parseAsCsv(String key, String value, Function<String, String> valueProcessor) {
- String cleanValue = MultivalueProperty.trimFieldsAndRemoveEmptyFields(value);
- List<String> result = new ArrayList<>();
- try (CSVParser csvParser = CSVFormat.RFC4180
- .withHeader((String) null)
- .withIgnoreEmptyLines()
- .withIgnoreSurroundingSpaces()
- .parse(new StringReader(cleanValue))) {
- List<CSVRecord> records = csvParser.getRecords();
- if (records.isEmpty()) {
- return ArrayUtils.EMPTY_STRING_ARRAY;
- }
- processRecords(result, records, valueProcessor);
- return result.toArray(new String[result.size()]);
- } catch (IOException e) {
- throw new IllegalStateException("Property: '" + key + "' doesn't contain a valid CSV value: '" + value + "'", e);
- }
- }
-
- /**
- * In most cases we expect a single record. <br>Having multiple records means the input value was splitted over multiple lines (this is common in Maven).
- * For example:
- * <pre>
- * <sonar.exclusions>
- * src/foo,
- * src/bar,
- * src/biz
- * <sonar.exclusions>
- * </pre>
- * In this case records will be merged to form a single list of items. Last item of a record is appended to first item of next record.
- * <p>
- * This is a very curious case, but we try to preserve line break in the middle of an item:
- * <pre>
- * <sonar.exclusions>
- * a
- * b,
- * c
- * <sonar.exclusions>
- * </pre>
- * will produce ['a\nb', 'c']
- */
- private static void processRecords(List<String> result, List<CSVRecord> records, Function<String, String> valueProcessor) {
- for (CSVRecord csvRecord : records) {
- Iterator<String> it = csvRecord.iterator();
- if (!result.isEmpty()) {
- String next = it.next();
- if (!next.isEmpty()) {
- int lastItemIdx = result.size() - 1;
- String previous = result.get(lastItemIdx);
- if (previous.isEmpty()) {
- result.set(lastItemIdx, valueProcessor.apply(next));
- } else {
- result.set(lastItemIdx, valueProcessor.apply(previous + "\n" + next));
- }
- }
- }
- it.forEachRemaining(s -> {
- String apply = valueProcessor.apply(s);
- result.add(apply);
- });
- }
- }
-
- /**
- * Removes the empty fields from the value of a multi-value property from empty fields, including trimming each field.
- * <p>
- * Quotes can be used to prevent an empty field to be removed (as it is used to preserve empty spaces).
- * <ul>
- * <li>{@code "" => ""}</li>
- * <li>{@code " " => ""}</li>
- * <li>{@code "," => ""}</li>
- * <li>{@code ",," => ""}</li>
- * <li>{@code ",,," => ""}</li>
- * <li>{@code ",a" => "a"}</li>
- * <li>{@code "a," => "a"}</li>
- * <li>{@code ",a," => "a"}</li>
- * <li>{@code "a,,b" => "a,b"}</li>
- * <li>{@code "a, ,b" => "a,b"}</li>
- * <li>{@code "a,\"\",b" => "a,b"}</li>
- * <li>{@code "\"a\",\"b\"" => "\"a\",\"b\""}</li>
- * <li>{@code "\" a \",\"b \"" => "\" a \",\"b \""}</li>
- * <li>{@code "\"a\",\"\",\"b\"" => "\"a\",\"\",\"b\""}</li>
- * <li>{@code "\"a\",\" \",\"b\"" => "\"a\",\" \",\"b\""}</li>
- * <li>{@code "\" a,,b,c \",\"d \"" => "\" a,,b,c \",\"d \""}</li>
- * <li>{@code "a,\" \",b" => "ab"]}</li>
- * </ul>
- */
- static String trimFieldsAndRemoveEmptyFields(String str) {
- char[] chars = str.toCharArray();
- char[] res = new char[chars.length];
- /*
- * set when reading the first non trimmable char after a separator char (or the beginning of the string)
- * unset when reading a separator
- */
- boolean inField = false;
- boolean inQuotes = false;
- int i = 0;
- int resI = 0;
- for (; i < chars.length; i++) {
- boolean isSeparator = chars[i] == ',';
- if (!inQuotes && isSeparator) {
- // exiting field (may already be unset)
- inField = false;
- if (resI > 0) {
- resI = retroTrim(res, resI);
- }
- } else {
- boolean isTrimmed = !inQuotes && istrimmable(chars[i]);
- if (isTrimmed && !inField) {
- // we haven't meet any non trimmable char since the last separator yet
- continue;
- }
-
- boolean isEscape = isEscapeChar(chars[i]);
- if (isEscape) {
- inQuotes = !inQuotes;
- }
-
- // add separator as we already had one field
- if (!inField && resI > 0) {
- res[resI] = ',';
- resI++;
- }
-
- // register in field (may already be set)
- inField = true;
- // copy current char
- res[resI] = chars[i];
- resI++;
- }
- }
- // inQuotes can only be true at this point if quotes are unbalanced
- if (!inQuotes) {
- // trim end of str
- resI = retroTrim(res, resI);
- }
- return new String(res, 0, resI);
- }
-
- private static boolean isEscapeChar(char aChar) {
- return aChar == '"';
- }
-
- private static boolean istrimmable(char aChar) {
- return aChar <= ' ';
- }
-
- /**
- * Reads from index {@code resI} to the beginning into {@code res} looking up the location of the trimmable char with
- * the lowest index before encountering a non-trimmable char.
- * <p>
- * This basically trims {@code res} from any trimmable char at its end.
- *
- * @return index of next location to put new char in res
- */
- private static int retroTrim(char[] res, int resI) {
- int i = resI;
- while (i >= 1) {
- if (!istrimmable(res[i - 1])) {
- return i;
- }
- i--;
- }
- return i;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.config.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.internal;
-
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.Scanner;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.Version;
-
-import static org.apache.commons.lang.StringUtils.trimToEmpty;
-
-/**
- * For internal use
- *
- * @since 7.8
- */
-public class MetadataLoader {
-
- private static final String VERSION_FILE_PATH = "/sonar-api-version.txt";
- private static final String EDITION_FILE_PATH = "/sonar-edition.txt";
-
- private MetadataLoader() {
- // only static methods
- }
-
- public static Version loadVersion(System2 system) {
- try {
- URL url = system.getResource(VERSION_FILE_PATH);
- Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name());
- String versionInFile = scanner.nextLine();
- return Version.parse(versionInFile);
- } catch (IOException e) {
- throw new IllegalStateException("Can not load " + VERSION_FILE_PATH + " from classpath ", e);
- }
- }
-
- public static SonarEdition loadEdition(System2 system) {
- try {
- URL url = system.getResource(EDITION_FILE_PATH);
- if (url == null) {
- return SonarEdition.COMMUNITY;
- }
- Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8.name());
- String editionInFile = scanner.nextLine();
- return parseEdition(editionInFile);
- } catch (IOException e) {
- throw new IllegalStateException("Can not load " + EDITION_FILE_PATH + " from classpath", e);
- }
- }
-
- static SonarEdition parseEdition(String edition) {
- String str = trimToEmpty(edition.toUpperCase());
- try {
- return SonarEdition.valueOf(str);
- } catch (IllegalArgumentException e) {
- throw new IllegalStateException(String.format("Invalid edition found in '%s': '%s'", EDITION_FILE_PATH, str));
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.internal;
-
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.MapSettings;
-
-/**
- * Implementation of {@link Plugin.Context} that plugins could use in their unit tests.
- *
- * Example:
- *
- * <pre>
- * import org.sonar.api.internal.SonarRuntimeImpl;
- * import org.sonar.api.config.internal.MapSettings;
- *
- * ...
- *
- * SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 1), SonarQubeSide.SCANNER);
- * MapSettings settings = new MapSettings().setProperty("foo", "bar");
- * Plugin.Context context = new PluginContextImpl.Builder()
- * .setSonarRuntime(runtime)
- * .setBootConfiguration(settings.asConfig());
- * .build();
- * </pre>
- *
- * @since 7.1
- */
-public class PluginContextImpl extends Plugin.Context {
-
- private final Configuration bootConfiguration;
-
- private PluginContextImpl(Builder builder) {
- super(builder.sonarRuntime);
- this.bootConfiguration = builder.bootConfiguration != null ? builder.bootConfiguration : new MapSettings().asConfig();
- }
-
- @Override
- public Configuration getBootConfiguration() {
- return bootConfiguration;
- }
-
- public static class Builder {
- private SonarRuntime sonarRuntime;
- private Configuration bootConfiguration;
-
- /**
- * Required.
- * @see SonarRuntimeImpl
- * @return this
- */
- public Builder setSonarRuntime(SonarRuntime r) {
- this.sonarRuntime = r;
- return this;
- }
-
- /**
- * If not set, then an empty configuration is used.
- * @return this
- */
- public Builder setBootConfiguration(Configuration c) {
- this.bootConfiguration = c;
- return this;
- }
-
- public Plugin.Context build() {
- return new PluginContextImpl(this);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.internal;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.SonarProduct;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.utils.Version;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-/**
- * @since 6.0
- */
-@Immutable
-public class SonarRuntimeImpl implements SonarRuntime {
-
- private final Version version;
- private final SonarProduct product;
- private final SonarQubeSide sonarQubeSide;
- private final SonarEdition edition;
-
- private SonarRuntimeImpl(Version version, SonarProduct product, @Nullable SonarQubeSide sonarQubeSide, @Nullable SonarEdition edition) {
- this.edition = edition;
- requireNonNull(product);
- checkArgument((product == SonarProduct.SONARQUBE) == (sonarQubeSide != null), "sonarQubeSide should be provided only for SonarQube product");
- checkArgument((product == SonarProduct.SONARQUBE) == (edition != null), "edition should be provided only for SonarQube product");
- this.version = requireNonNull(version);
- this.product = product;
- this.sonarQubeSide = sonarQubeSide;
- }
-
- @Override
- public Version getApiVersion() {
- return version;
- }
-
- @Override
- public SonarProduct getProduct() {
- return product;
- }
-
- @Override
- public SonarQubeSide getSonarQubeSide() {
- if (sonarQubeSide == null) {
- throw new UnsupportedOperationException("Can only be called in SonarQube");
- }
- return sonarQubeSide;
- }
-
- @Override
- public SonarEdition getEdition() {
- if (sonarQubeSide == null) {
- throw new UnsupportedOperationException("Can only be called in SonarQube");
- }
- return edition;
- }
-
- /**
- * Create an instance for SonarQube runtime environment.
- */
- public static SonarRuntime forSonarQube(Version version, SonarQubeSide side, SonarEdition edition) {
- return new SonarRuntimeImpl(version, SonarProduct.SONARQUBE, side, edition);
- }
-
- /**
- * Create an instance for SonarLint runtime environment.
- */
- public static SonarRuntime forSonarLint(Version version) {
- return new SonarRuntimeImpl(version, SonarProduct.SONARLINT, null, null);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
*/
public Rule setStatus(String status) {
if (!STATUS_LIST.contains(status)) {
- throw new SonarException("The status of a rule can only contain : " + String.join(", ", STATUS_LIST));
+ throw new IllegalStateException("The status of a rule can only contain : " + String.join(", ", STATUS_LIST));
}
this.status = status;
return this;
/**
* Instantiated by core but not by plugins, except for their tests.
*/
- interface Context {
+ abstract class Context {
/*
* New builder for {@link org.sonar.api.server.rule.RulesDefinition.Repository}.
* <br>
* the FbContrib plugin contributes to the Findbugs plugin rules. In this case no need
* to execute {@link org.sonar.api.server.rule.RulesDefinition.NewRepository#setName(String)}
*/
- NewRepository createRepository(String key, String language);
+ public abstract NewRepository createRepository(String key, String language);
/**
* Creates a repository of rules from external rule engines.
*
* @since 7.2
*/
- NewRepository createExternalRepository(String engineId, String language);
+ public abstract NewRepository createExternalRepository(String engineId, String language);
/**
* @deprecated since 5.2. Simply use {@link #createRepository(String, String)}
*/
@Deprecated
- NewRepository extendRepository(String key, String language);
+ public abstract NewRepository extendRepository(String key, String language);
@CheckForNull
- Repository repository(String key);
+ public abstract Repository repository(String key);
- List<Repository> repositories();
+ public abstract List<Repository> repositories();
/**
* @deprecated returns empty list since 5.2. Concept of "extended repository" was misleading and not valuable. Simply declare
* repositories and use {@link #repositories()}. See http://jira.sonarsource.com/browse/SONAR-6709
*/
@Deprecated
- List<ExtendedRepository> extendedRepositories(String repositoryKey);
+ public abstract List<ExtendedRepository> extendedRepositories(String repositoryKey);
/**
* @deprecated returns empty list since 5.2. Concept of "extended repository" was misleading and not valuable. Simply declare
* repositories and use {@link #repositories()}. See http://jira.sonarsource.com/browse/SONAR-6709
*/
@Deprecated
- List<ExtendedRepository> extendedRepositories();
+ public abstract List<ExtendedRepository> extendedRepositories();
- void setCurrentPluginKey(@Nullable String pluginKey);
+ public abstract void setCurrentPluginKey(@Nullable String pluginKey);
}
interface NewExtendedRepository {
DebtRemediationFunction create(DebtRemediationFunction.Type type, @Nullable String gapMultiplier, @Nullable String baseEffort);
}
- interface NewRule {
+ abstract class NewRule {
- String key();
+ public abstract String key();
/**
* @since 7.1
*/
@CheckForNull
- RuleScope scope();
+ public abstract RuleScope scope();
/**
* @since 7.1
*/
- NewRule setScope(RuleScope scope);
+ public abstract NewRule setScope(RuleScope scope);
/**
* Required rule name
*/
- NewRule setName(String s);
+ public abstract NewRule setName(String s);
- NewRule setTemplate(boolean template);
+ public abstract NewRule setTemplate(boolean template);
/**
* Should this rule be enabled by default. For example in SonarLint standalone.
*
* @since 6.0
*/
- NewRule setActivatedByDefault(boolean activatedByDefault);
+ public abstract NewRule setActivatedByDefault(boolean activatedByDefault);
- NewRule setSeverity(String s);
+ public abstract NewRule setSeverity(String s);
/**
* The type as defined by the SonarQube Quality Model.
*
* @since 5.5
*/
- NewRule setType(RuleType t);
+ public abstract NewRule setType(RuleType t);
/**
* The optional description, in HTML format, has no max length. It's exclusive with markdown description
* (see {@link #setMarkdownDescription(String)})
*/
- NewRule setHtmlDescription(@Nullable String s);
+ public abstract NewRule setHtmlDescription(@Nullable String s);
/**
* Load description from a file available in classpath. Example : <code>setHtmlDescription(getClass().getResource("/myrepo/Rule1234.html")</code>
*/
- NewRule setHtmlDescription(@Nullable URL classpathUrl);
+ public abstract NewRule setHtmlDescription(@Nullable URL classpathUrl);
/**
* The optional description, in a restricted Markdown format, has no max length. It's exclusive with HTML description
* (see {@link #setHtmlDescription(String)})
*/
- NewRule setMarkdownDescription(@Nullable String s);
+ public abstract NewRule setMarkdownDescription(@Nullable String s);
/**
* Load description from a file available in classpath. Example : {@code setMarkdownDescription(getClass().getResource("/myrepo/Rule1234.md")}
*/
- NewRule setMarkdownDescription(@Nullable URL classpathUrl);
+ public abstract NewRule setMarkdownDescription(@Nullable URL classpathUrl);
/**
* Default value is {@link org.sonar.api.rule.RuleStatus#READY}. The value
* {@link org.sonar.api.rule.RuleStatus#REMOVED} is not accepted and raises an
* {@link java.lang.IllegalArgumentException}.
*/
- NewRule setStatus(RuleStatus status);
+ public abstract NewRule setStatus(RuleStatus status);
/**
* SQALE sub-characteristic. See http://www.sqale.org
* @deprecated in 5.5. SQALE Quality Model is replaced by SonarQube Quality Model. This method does nothing.
* See https://jira.sonarsource.com/browse/MMF-184
*/
- NewRule setDebtSubCharacteristic(@Nullable String s);
+ @Deprecated
+ public abstract NewRule setDebtSubCharacteristic(@Nullable String s);
/**
* Factory of {@link org.sonar.api.server.debt.DebtRemediationFunction}
*/
- DebtRemediationFunctions debtRemediationFunctions();
+ public abstract DebtRemediationFunctions debtRemediationFunctions();
/**
* @see #debtRemediationFunctions()
*/
- NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn);
+ public abstract NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction fn);
/**
* @deprecated since 5.5, replaced by {@link #setGapDescription(String)}
*/
@Deprecated
- NewRule setEffortToFixDescription(@Nullable String s);
+ public abstract NewRule setEffortToFixDescription(@Nullable String s);
/**
* For rules that use LINEAR or LINEAR_OFFSET remediation functions, the meaning
* remediation function gap multiplier/base effort would be something like
* "Effort to test one uncovered condition".
*/
- NewRule setGapDescription(@Nullable String s);
+ public abstract NewRule setGapDescription(@Nullable String s);
/**
* Create a parameter with given unique key. Max length of key is 128 characters.
*/
- NewParam createParam(String paramKey);
+ public abstract NewParam createParam(String paramKey);
@CheckForNull
- NewParam param(String paramKey);
+ public abstract NewParam param(String paramKey);
- Collection<NewParam> params();
+ public abstract Collection<NewParam> params();
/**
* @see RuleTagFormat
*/
- NewRule addTags(String... list);
+ public abstract NewRule addTags(String... list);
/**
* @see RuleTagFormat
*/
- NewRule setTags(String... list);
+ public abstract NewRule setTags(String... list);
/**
* @since 7.3
*/
- NewRule addOwaspTop10(OwaspTop10... standards);
+ public abstract NewRule addOwaspTop10(OwaspTop10... standards);
/**
* @since 7.3
*/
- NewRule addCwe(int... nums);
+ public abstract NewRule addCwe(int... nums);
/**
* Optional key that can be used by the rule engine. Not displayed
* in webapp. For example the Java Checkstyle plugin feeds this field
* with the internal path ("Checker/TreeWalker/AnnotationUseStyle").
*/
- NewRule setInternalKey(@Nullable String s);
+ public abstract NewRule setInternalKey(@Nullable String s);
/**
* Register a repository and key under which this rule used to be known
* @see Rule#deprecatedRuleKeys
* @since 7.1
*/
- NewRule addDeprecatedRuleKey(String repository, String key);
-
- @Override
- String toString();
+ public abstract NewRule addDeprecatedRuleKey(String repository, String key);
}
@Immutable
}
- interface NewParam {
- String key();
+ abstract class NewParam {
+ public abstract String key();
- NewParam setName(@Nullable String s);
+ public abstract NewParam setName(@Nullable String s);
- NewParam setType(RuleParamType t);
+ public abstract NewParam setType(RuleParamType t);
/**
* Plain-text description. Can be null. Max length is 4000 characters.
*/
- NewParam setDescription(@Nullable String s);
+ public abstract NewParam setDescription(@Nullable String s);
/**
* Empty default value will be converted to null. Max length is 4000 characters.
*/
- NewParam setDefaultValue(@Nullable String s);
+ public abstract NewParam setDefaultValue(@Nullable String s);
}
@Immutable
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.server.ws.internal;
-
-import java.io.InputStream;
-import org.sonar.api.server.ws.Request;
-
-public class PartImpl implements Request.Part {
-
- private final InputStream inputStream;
- private final String fileName;
-
- public PartImpl(InputStream inputStream, String fileName) {
- this.inputStream = inputStream;
- this.fileName = fileName;
- }
-
- @Override
- public InputStream getInputStream() {
- return inputStream;
- }
-
- @Override
- public String getFileName() {
- return fileName;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.server.ws.internal;
-
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.io.IOUtils;
-import org.sonar.api.server.ws.LocalConnector;
-import org.sonar.api.server.ws.Request;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.Objects.requireNonNull;
-
-/**
- * Fake implementation of {@link org.sonar.api.server.ws.Request} used
- * for testing. Call the method {@link #setParam(String, String)} to
- * emulate some parameter values.
- */
-public class SimpleGetRequest extends Request {
-
- private final Map<String, String[]> params = new HashMap<>();
- private final Map<String, Part> parts = new HashMap<>();
- private final Map<String, String> headers = new HashMap<>();
- private String mediaType = "application/json";
- private String path;
-
- @Override
- public String method() {
- return "GET";
- }
-
- @Override
- public String getMediaType() {
- return mediaType;
- }
-
- public SimpleGetRequest setMediaType(String mediaType) {
- requireNonNull(mediaType);
- this.mediaType = mediaType;
- return this;
- }
-
- @Override
- public boolean hasParam(String key) {
- return params.keySet().contains(key);
- }
-
- @Override
- public String param(String key) {
- String[] strings = params.get(key);
- return strings == null || strings.length == 0 ? null : strings[0];
- }
-
- @Override
- public List<String> multiParam(String key) {
- String value = param(key);
- return value == null ? emptyList() : singletonList(value);
- }
-
- @Override
- @CheckForNull
- public List<String> paramAsStrings(String key) {
- String value = param(key);
- if (value == null) {
- return null;
- }
-
- return Arrays.stream(value.split(",")).map(String::trim).filter(x -> !x.isEmpty()).collect(Collectors.toList());
- }
-
- @Override
- public InputStream paramAsInputStream(String key) {
- return IOUtils.toInputStream(param(key), UTF_8);
- }
-
- public SimpleGetRequest setParam(String key, @Nullable String value) {
- if (value != null) {
- params.put(key, new String[] {value});
- }
- return this;
- }
-
- @Override
- public Map<String, String[]> getParams() {
- return params;
- }
-
- @Override
- public Part paramAsPart(String key) {
- return parts.get(key);
- }
-
- public SimpleGetRequest setPart(String key, InputStream input, String fileName) {
- parts.put(key, new PartImpl(input, fileName));
- return this;
- }
-
- @Override
- public LocalConnector localConnector() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getPath() {
- return path;
- }
-
- public SimpleGetRequest setPath(String path) {
- this.path = path;
- return this;
- }
-
- @Override
- public Optional<String> header(String name) {
- return Optional.ofNullable(headers.get(name));
- }
-
- public SimpleGetRequest setHeader(String name, String value) {
- headers.put(name, value);
- return this;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.server.ws.internal;
-
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.server.ws.LocalConnector;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.WebService;
-
-import static java.lang.String.format;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.Objects.requireNonNull;
-import static org.apache.commons.lang.StringUtils.defaultString;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-/**
- * @since 4.2
- */
-public abstract class ValidatingRequest extends Request {
-
- private static final String COMMA_SPLITTER = ",";
- private WebService.Action action;
- private LocalConnector localConnector;
-
- public void setAction(WebService.Action action) {
- this.action = action;
- }
-
- public WebService.Action action() {
- return action;
- }
-
- @Override
- public LocalConnector localConnector() {
- requireNonNull(localConnector, "Local connector has not been set");
- return localConnector;
- }
-
- public void setLocalConnector(LocalConnector lc) {
- this.localConnector = lc;
- }
-
- @Override
- @CheckForNull
- public String param(String key) {
- WebService.Param definition = action.param(key);
- String rawValue = readParam(key, definition);
- String rawValueOrDefault = defaultString(rawValue, definition.defaultValue());
- String value = rawValueOrDefault == null ? null : trim(rawValueOrDefault);
- validateRequiredValue(key, definition, rawValue);
- if (value == null) {
- return null;
- }
- validatePossibleValues(key, value, definition);
- validateMaximumLength(key, definition, rawValueOrDefault);
- validateMinimumLength(key, definition, rawValueOrDefault);
- validateMaximumValue(key, definition, value);
- return value;
- }
-
- @Override
- public List<String> multiParam(String key) {
- WebService.Param definition = action.param(key);
- List<String> values = readMultiParamOrDefaultValue(key, definition);
- return validateValues(values, definition);
- }
-
- private static String trim(String s) {
- int begin;
- for (begin = 0; begin < s.length(); begin++) {
- if (!Character.isWhitespace(s.charAt(begin))) {
- break;
- }
- }
-
- int end;
- for (end = s.length(); end > begin; end--) {
- if (!Character.isWhitespace(s.charAt(end - 1))) {
- break;
- }
- }
- return s.substring(begin, end);
- }
-
- @Override
- @CheckForNull
- public InputStream paramAsInputStream(String key) {
- return readInputStreamParam(key);
- }
-
- @Override
- @CheckForNull
- public Part paramAsPart(String key) {
- return readPart(key);
- }
-
- @CheckForNull
- @Override
- public List<String> paramAsStrings(String key) {
- WebService.Param definition = action.param(key);
- String value = defaultString(readParam(key, definition), definition.defaultValue());
- if (value == null) {
- return null;
- }
- List<String> values = Arrays.stream(value.split(COMMA_SPLITTER))
- .map(String::trim)
- .filter(s -> !s.isEmpty())
- .collect(Collectors.toList());
- return validateValues(values, definition);
- }
-
- @CheckForNull
- @Override
- public <E extends Enum<E>> List<E> paramAsEnums(String key, Class<E> enumClass) {
- List<String> values = paramAsStrings(key);
- if (values == null) {
- return null;
- }
- return values.stream()
- .filter(s -> !s.isEmpty())
- .map(value -> Enum.valueOf(enumClass, value))
- .collect(Collectors.toList());
- }
-
- @CheckForNull
- private String readParam(String key, @Nullable WebService.Param definition) {
- checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key());
- String deprecatedKey = definition.deprecatedKey();
- return deprecatedKey != null ? defaultString(readParam(deprecatedKey), readParam(key)) : readParam(key);
- }
-
- private List<String> readMultiParamOrDefaultValue(String key, @Nullable WebService.Param definition) {
- checkArgument(definition != null, "BUG - parameter '%s' is undefined for action '%s'", key, action.key());
-
- List<String> keyValues = readMultiParam(key);
- if (!keyValues.isEmpty()) {
- return keyValues;
- }
-
- String deprecatedKey = definition.deprecatedKey();
- List<String> deprecatedKeyValues = deprecatedKey == null ? emptyList() : readMultiParam(deprecatedKey);
- if (!deprecatedKeyValues.isEmpty()) {
- return deprecatedKeyValues;
- }
-
- String defaultValue = definition.defaultValue();
- return defaultValue == null ? emptyList() : singletonList(defaultValue);
- }
-
- @CheckForNull
- protected abstract String readParam(String key);
-
- protected abstract List<String> readMultiParam(String key);
-
- @CheckForNull
- protected abstract InputStream readInputStreamParam(String key);
-
- @CheckForNull
- protected abstract Part readPart(String key);
-
- private static List<String> validateValues(List<String> values, WebService.Param definition) {
- Integer maximumValues = definition.maxValuesAllowed();
- checkArgument(maximumValues == null || values.size() <= maximumValues, "'%s' can contains only %s values, got %s", definition.key(), maximumValues, values.size());
- values.forEach(value -> validatePossibleValues(definition.key(), value, definition));
- return values;
- }
-
- private static void validatePossibleValues(String key, String value, WebService.Param definition) {
- Set<String> possibleValues = definition.possibleValues();
- if (possibleValues == null) {
- return;
- }
- checkArgument(possibleValues.contains(value), "Value of parameter '%s' (%s) must be one of: %s", key, value, possibleValues);
- }
-
- private static void validateMaximumLength(String key, WebService.Param definition, String valueOrDefault) {
- Integer maximumLength = definition.maximumLength();
- if (maximumLength == null) {
- return;
- }
- int valueLength = valueOrDefault.length();
- checkArgument(valueLength <= maximumLength, "'%s' length (%s) is longer than the maximum authorized (%s)", key, valueLength, maximumLength);
- }
-
- private static void validateMinimumLength(String key, WebService.Param definition, String valueOrDefault) {
- Integer minimumLength = definition.minimumLength();
- if (minimumLength == null) {
- return;
- }
- int valueLength = valueOrDefault.length();
- checkArgument(valueLength >= minimumLength, "'%s' length (%s) is shorter than the minimum authorized (%s)", key, valueLength, minimumLength);
- }
-
- private static void validateMaximumValue(String key, WebService.Param definition, String value) {
- Integer maximumValue = definition.maximumValue();
- if (maximumValue == null) {
- return;
- }
- int valueAsInt = validateAsNumeric(key, value);
- checkArgument(valueAsInt <= maximumValue, "'%s' value (%s) must be less than %s", key, valueAsInt, maximumValue);
- }
-
- private static void validateRequiredValue(String key, WebService.Param definition, String value) {
- boolean required = definition.isRequired();
- if (required) {
- checkArgument(value != null, format(MSG_PARAMETER_MISSING, key));
- }
- }
-
- private static int validateAsNumeric(String key, String value) {
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException exception) {
- throw new IllegalArgumentException(format("'%s' value '%s' cannot be parsed as an integer", key, value), exception);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.server.ws.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
package org.sonar.api.utils;
public class Preconditions {
+ private Preconditions() {
+ // static only
+ }
+
public static void checkArgument(boolean condition, String message) {
if (!condition) {
throw new IllegalArgumentException(message);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import java.util.Random;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.Supplier;
-import org.sonar.api.utils.System2;
-
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-/**
- * A subclass of {@link System2} which implementation of {@link System2#now()} always return a bigger value than the
- * previous returned value.
- * <p>
- * This class is intended to be used in Unit tests.
- * </p>
- */
-public class AlwaysIncreasingSystem2 extends System2 {
- private final AtomicLong now;
- private final long increment;
-
- private AlwaysIncreasingSystem2(Supplier<Long> initialValueSupplier, long increment) {
- checkArgument(increment > 0, "increment must be > 0");
- long initialValue = initialValueSupplier.get();
- checkArgument(initialValue >= 0, "Initial value must be >= 0");
- this.now = new AtomicLong(initialValue);
- this.increment = increment;
- }
-
- public AlwaysIncreasingSystem2(long increment) {
- this(AlwaysIncreasingSystem2::randomInitialValue, increment);
- }
-
- public AlwaysIncreasingSystem2(long initialValue, int increment) {
- this(() -> initialValue, increment);
- }
-
- /**
- * Values returned by {@link #now()} will start with a random value and increment by 100.
- */
- public AlwaysIncreasingSystem2() {
- this(AlwaysIncreasingSystem2::randomInitialValue, 100);
- }
-
- @Override
- public long now() {
- return now.getAndAdd(increment);
- }
-
- private static long randomInitialValue() {
- return (long) Math.abs(new Random().nextInt(2_000_000));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import java.nio.file.FileVisitResult;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.utils.TempFolder;
-
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-public class DefaultTempFolder implements TempFolder {
- private static final Logger LOG = Loggers.get(DefaultTempFolder.class);
-
- private final File tempDir;
- private final boolean deleteOnExit;
-
- public DefaultTempFolder(File tempDir) {
- this(tempDir, false);
- }
-
- public DefaultTempFolder(File tempDir, boolean deleteOnExit) {
- this.tempDir = tempDir;
- this.deleteOnExit = deleteOnExit;
- }
-
- @Override
- public File newDir() {
- return createTempDir(tempDir.toPath()).toFile();
- }
-
- private static Path createTempDir(Path baseDir) {
- try {
- return Files.createTempDirectory(baseDir, null);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to create temp directory", e);
- }
- }
-
- @Override
- public File newDir(String name) {
- File dir = new File(tempDir, name);
- try {
- FileUtils.forceMkdir(dir);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to create temp directory - " + dir, e);
- }
- return dir;
- }
-
- @Override
- public File newFile() {
- return newFile(null, null);
- }
-
- @Override
- public File newFile(@Nullable String prefix, @Nullable String suffix) {
- return createTempFile(tempDir.toPath(), prefix, suffix).toFile();
- }
-
- private static Path createTempFile(Path baseDir, String prefix, String suffix) {
- try {
- return Files.createTempFile(baseDir, prefix, suffix);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to create temp file", e);
- }
- }
-
- public void clean() {
- try {
- if (tempDir.exists()) {
- Files.walkFileTree(tempDir.toPath(), DeleteRecursivelyFileVisitor.INSTANCE);
- }
- } catch (IOException e) {
- LOG.error("Failed to delete temp folder", e);
- }
- }
-
- public void stop() {
- if (deleteOnExit) {
- clean();
- }
- }
-
- private static final class DeleteRecursivelyFileVisitor extends SimpleFileVisitor<Path> {
- public static final DeleteRecursivelyFileVisitor INSTANCE = new DeleteRecursivelyFileVisitor();
-
- @Override
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
- Files.deleteIfExists(file);
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
- Files.deleteIfExists(dir);
- return FileVisitResult.CONTINUE;
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import org.apache.commons.lang.StringUtils;
-import org.junit.rules.ExternalResource;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-import org.sonar.api.utils.TempFolder;
-
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Implementation of {@link org.sonar.api.utils.TempFolder} to be used
- * only in JUnit tests. It wraps {@link org.junit.rules.TemporaryFolder}.
- * <br>
- * Example:
- * <pre>
- * public class MyTest {
- * @@org.junit.Rule
- * public JUnitTempFolder temp = new JUnitTempFolder();
- *
- * @@org.junit.Test
- * public void myTest() throws Exception {
- * File dir = temp.newDir();
- * // ...
- * }
- * }
- * </pre>
- *
- * @since 5.1
- */
-public class JUnitTempFolder extends ExternalResource implements TempFolder {
-
- private final TemporaryFolder junit = new TemporaryFolder();
-
- @Override
- public Statement apply(Statement base, Description description) {
- return junit.apply(base, description);
- }
-
- @Override
- protected void before() throws Throwable {
- junit.create();
- }
-
- @Override
- protected void after() {
- junit.delete();
- }
-
- @Override
- public File newDir() {
- try {
- return junit.newFolder();
- } catch (IOException e) {
- throw new IllegalStateException("Fail to create temp dir", e);
- }
- }
-
- @Override
- public File newDir(String name) {
- try {
- return junit.newFolder(name);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to create temp dir", e);
- }
- }
-
- @Override
- public File newFile() {
- try {
- return junit.newFile();
- } catch (IOException e) {
- throw new IllegalStateException("Fail to create temp file", e);
- }
- }
-
- @Override
- public File newFile(@Nullable String prefix, @Nullable String suffix) {
- try {
- return junit.newFile(StringUtils.defaultString(prefix) + "-" + StringUtils.defaultString(suffix));
- } catch (IOException e) {
- throw new IllegalStateException("Fail to create temp file", e);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import org.sonar.api.Startable;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.TempFolder;
-
-@ServerSide
-public class TempFolderCleaner implements Startable {
-
- private TempFolder defaultTempFolder;
-
- public TempFolderCleaner(TempFolder defaultTempFolder) {
- this.defaultTempFolder = defaultTempFolder;
- }
-
- /**
- * This method should not be renamed. It follows the naming convention
- * defined by IoC container.
- */
- @Override
- public void start() {
- // Nothing to do
- }
-
- /**
- * This method should not be renamed. It follows the naming convention
- * defined by IoC container.
- */
- @Override
- public void stop() {
- ((DefaultTempFolder) defaultTempFolder).clean();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import java.util.TimeZone;
-import org.sonar.api.utils.System2;
-
-public class TestSystem2 extends System2 {
-
- private long now = 0L;
- private TimeZone defaultTimeZone = getDefaultTimeZone();
-
- public TestSystem2 setNow(long l) {
- this.now = l;
- return this;
- }
-
- @Override
- public long now() {
- if (now <= 0L) {
- throw new IllegalStateException("Method setNow() was not called by test");
- }
- return now;
- }
-
- public TestSystem2 setDefaultTimeZone(TimeZone defaultTimeZone) {
- this.defaultTimeZone = defaultTimeZone;
- return this;
- }
-
- @Override
- public TimeZone getDefaultTimeZone() {
- return defaultTimeZone;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import java.io.Serializable;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-
-/**
- * @since 4.2
- */
-public class WorkDuration implements Serializable {
-
- static final int DAY_POSITION_IN_LONG = 10_000;
- static final int HOUR_POSITION_IN_LONG = 100;
- static final int MINUTE_POSITION_IN_LONG = 1;
-
- public enum UNIT {
- DAYS, HOURS, MINUTES
- }
-
- private int hoursInDay;
-
- private long durationInMinutes;
- private int days;
- private int hours;
- private int minutes;
-
- private WorkDuration(long durationInMinutes, int days, int hours, int minutes, int hoursInDay) {
- this.durationInMinutes = durationInMinutes;
- this.days = days;
- this.hours = hours;
- this.minutes = minutes;
- this.hoursInDay = hoursInDay;
- }
-
- public static WorkDuration create(int days, int hours, int minutes, int hoursInDay) {
- long durationInSeconds = 60L * days * hoursInDay;
- durationInSeconds += 60L * hours;
- durationInSeconds += minutes;
- return new WorkDuration(durationInSeconds, days, hours, minutes, hoursInDay);
- }
-
- public static WorkDuration createFromValueAndUnit(int value, UNIT unit, int hoursInDay) {
- switch (unit) {
- case DAYS:
- return create(value, 0, 0, hoursInDay);
- case HOURS:
- return create(0, value, 0, hoursInDay);
- case MINUTES:
- return create(0, 0, value, hoursInDay);
- default:
- throw new IllegalStateException("Cannot create work duration");
- }
- }
-
- static WorkDuration createFromLong(long duration, int hoursInDay) {
- int days = 0;
- int hours = 0;
- int minutes = 0;
-
- long time = duration;
- Long currentTime = time / WorkDuration.DAY_POSITION_IN_LONG;
- if (currentTime > 0) {
- days = currentTime.intValue();
- time = time - (currentTime * WorkDuration.DAY_POSITION_IN_LONG);
- }
-
- currentTime = time / WorkDuration.HOUR_POSITION_IN_LONG;
- if (currentTime > 0) {
- hours = currentTime.intValue();
- time = time - (currentTime * WorkDuration.HOUR_POSITION_IN_LONG);
- }
-
- currentTime = time / WorkDuration.MINUTE_POSITION_IN_LONG;
- if (currentTime > 0) {
- minutes = currentTime.intValue();
- }
- return WorkDuration.create(days, hours, minutes, hoursInDay);
- }
-
- static WorkDuration createFromMinutes(long duration, int hoursInDay) {
- int days = (int)(duration / (double)hoursInDay / 60.0);
- Long currentDurationInMinutes = duration - (60L * days * hoursInDay);
- int hours = (int)(currentDurationInMinutes / 60.0);
- currentDurationInMinutes = currentDurationInMinutes - (60L * hours);
- return new WorkDuration(duration, days, hours, currentDurationInMinutes.intValue(), hoursInDay);
- }
-
- /**
- * Return the duration in number of working days.
- * For instance, 3 days and 4 hours will return 3.5 days (if hoursIndDay is 8).
- */
- public double toWorkingDays() {
- return durationInMinutes / 60d / hoursInDay;
- }
-
- /**
- * Return the duration using the following format DDHHMM, where DD is the number of days, HH is the number of months, and MM the number of minutes.
- * For instance, 3 days and 4 hours will return 030400 (if hoursIndDay is 8).
- */
- public long toLong() {
- int workingDays = days;
- int workingHours = hours;
- if (hours >= hoursInDay) {
- int nbAdditionalDays = hours / hoursInDay;
- workingDays += nbAdditionalDays;
- workingHours = hours - (nbAdditionalDays * hoursInDay);
- }
- return 1L * workingDays * DAY_POSITION_IN_LONG + workingHours * HOUR_POSITION_IN_LONG + minutes * MINUTE_POSITION_IN_LONG;
- }
-
- public long toMinutes() {
- return durationInMinutes;
- }
-
- public WorkDuration add(@Nullable WorkDuration with) {
- if (with != null) {
- return WorkDuration.createFromMinutes(this.toMinutes() + with.toMinutes(), this.hoursInDay);
- } else {
- return this;
- }
- }
-
- public WorkDuration subtract(@Nullable WorkDuration with) {
- if (with != null) {
- return WorkDuration.createFromMinutes(this.toMinutes() - with.toMinutes(), this.hoursInDay);
- } else {
- return this;
- }
- }
-
- public WorkDuration multiply(int factor) {
- return WorkDuration.createFromMinutes(this.toMinutes() * factor, this.hoursInDay);
- }
-
- public int days() {
- return days;
- }
-
- public int hours() {
- return hours;
- }
-
- public int minutes() {
- return minutes;
- }
-
- int hoursInDay() {
- return hoursInDay;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- WorkDuration that = (WorkDuration) o;
- return durationInMinutes == that.durationInMinutes;
-
- }
-
- @Override
- public int hashCode() {
- return (int) (durationInMinutes ^ (durationInMinutes >>> 32));
- }
-
- @Override
- public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.api.utils.internal;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
import java.util.Arrays;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.PluginContextImpl;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.context.PluginContextImpl;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.Version;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.sonar.api.batch.bootstrap.internal.ProjectBuilderContext;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.core.Is.is;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.batch.fs.internal;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.junit.Test;
-
-public class MetadataTest {
- @Test
- public void testRoundtrip() {
- Metadata metadata = new Metadata(10, 20, "hash", new int[] {1, 3}, new int[] {2, 4}, 5);
- assertThat(metadata.isEmpty()).isFalse();
- assertThat(metadata.lines()).isEqualTo(10);
- assertThat(metadata.nonBlankLines()).isEqualTo(20);
- assertThat(metadata.originalLineStartOffsets()).isEqualTo(new int[] {1, 3});
- assertThat(metadata.originalLineEndOffsets()).isEqualTo(new int[] {2, 4});
- assertThat(metadata.lastValidOffset()).isEqualTo(5);
- assertThat(metadata.hash()).isEqualTo("hash");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.batch.fs.internal;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.IndexedFile;
-import org.sonar.scanner.fs.DefaultIndexedFile;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PathPatternTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
- private Path baseDir;
-
- @Before
- public void setUp() throws IOException {
- baseDir = temp.newFolder().toPath();
- }
-
- @Test
- public void match_relative_path() {
- PathPattern pattern = PathPattern.create("**/*Foo.java");
- assertThat(pattern.toString()).isEqualTo("**/*Foo.java");
-
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.java", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isTrue();
-
- // case sensitive by default
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
-
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
- }
-
- @Test
- public void match_relative_path_and_insensitive_file_extension() throws Exception {
- PathPattern pattern = PathPattern.create("**/*Foo.java");
-
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isTrue();
-
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isFalse();
- }
-
- @Test
- public void match_absolute_path() throws Exception {
- PathPattern pattern = PathPattern.create("file:**/src/main/**Foo.java");
- assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
-
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.java", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isTrue();
-
- // case sensitive by default
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
-
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.java", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()))).isFalse();
- }
-
- @Test
- public void match_absolute_path_and_insensitive_file_extension() throws Exception {
- PathPattern pattern = PathPattern.create("file:**/src/main/**Foo.java");
- assertThat(pattern.toString()).isEqualTo("file:**/src/main/**Foo.java");
-
- IndexedFile indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/MyFoo.JAVA", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isTrue();
-
- indexedFile = new DefaultIndexedFile("ABCDE", baseDir, "src/main/java/org/Other.JAVA", null);
- assertThat(pattern.match(indexedFile.path(), Paths.get(indexedFile.relativePath()), false)).isFalse();
- }
-
- @Test
- public void create_array_of_patterns() {
- PathPattern[] patterns = PathPattern.create(new String[] {
- "**/src/main/**Foo.java",
- "file:**/src/main/**Bar.java"
- });
- assertThat(patterns).hasSize(2);
- assertThat(patterns[0].toString()).isEqualTo("**/src/main/**Foo.java");
- assertThat(patterns[1].toString()).isEqualTo("file:**/src/main/**Bar.java");
- }
-}
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.SonarException;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
-import org.sonar.scanner.rule.NewActiveRule;
import static org.assertj.core.api.Assertions.assertThat;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.rule;
+
+import com.google.common.collect.ImmutableMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class NewActiveRuleTest {
+
+ private NewActiveRule.Builder builder;
+
+ @Before
+ public void setBuilder() {
+ builder = new NewActiveRule.Builder();
+ }
+
+ @Test
+ public void builder_should_set_every_param() {
+ NewActiveRule rule = builder
+ .setRuleKey(RuleKey.of("foo", "bar"))
+ .setName("name")
+ .setSeverity(org.sonar.api.rule.Severity.CRITICAL)
+ .setParam("key", "value")
+ .setCreatedAt(1_000L)
+ .setUpdatedAt(1_000L)
+ .setInternalKey("internal_key")
+ .setLanguage("language")
+ .setTemplateRuleKey("templateRuleKey")
+ .setQProfileKey("qProfileKey")
+ .build();
+
+ assertThat(rule.ruleKey).isEqualTo(RuleKey.of("foo", "bar"));
+ assertThat(rule.name).isEqualTo("name");
+ assertThat(rule.severity).isEqualTo(org.sonar.api.rule.Severity.CRITICAL);
+ assertThat(rule.params).isEqualTo(ImmutableMap.of("key", "value"));
+ assertThat(rule.createdAt).isEqualTo(1_000L);
+ assertThat(rule.updatedAt).isEqualTo(1_000L);
+ assertThat(rule.internalKey).isEqualTo("internal_key");
+ assertThat(rule.language).isEqualTo("language");
+ assertThat(rule.templateRuleKey).isEqualTo("templateRuleKey");
+ assertThat(rule.qProfileKey).isEqualTo("qProfileKey");
+ }
+
+ @Test
+ public void severity_should_have_default_value() {
+ NewActiveRule rule = builder.build();
+ assertThat(rule.severity).isEqualTo(Severity.defaultSeverity());
+ }
+
+ @Test
+ public void params_should_be_empty_map_if_no_params() {
+ NewActiveRule rule = builder.build();
+ assertThat(rule.params).isEqualTo(ImmutableMap.of());
+ }
+
+ @Test
+ public void set_param_remove_param_if_value_is_null() {
+ NewActiveRule rule = builder
+ .setParam("foo", "bar")
+ .setParam("removed", "value")
+ .setParam("removed", null)
+ .build();
+ assertThat(rule.params).isEqualTo(ImmutableMap.of("foo", "bar"));
+ }
+}
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.platform.Server;
import static org.assertj.core.api.Assertions.assertThat;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.config.internal;
-
-import com.tngtech.java.junit.dataprovider.DataProvider;
-import com.tngtech.java.junit.dataprovider.DataProviderRunner;
-import com.tngtech.java.junit.dataprovider.UseDataProvider;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Random;
-import java.util.function.BiConsumer;
-import java.util.stream.IntStream;
-import org.assertj.core.data.Offset;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.sonar.api.Properties;
-import org.sonar.api.Property;
-import org.sonar.api.PropertyType;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-import org.sonar.api.utils.DateUtils;
-
-import static java.util.Collections.singletonList;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@RunWith(DataProviderRunner.class)
-public class MapSettingsTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- private PropertyDefinitions definitions;
-
- @Properties({
- @Property(key = "hello", name = "Hello", defaultValue = "world"),
- @Property(key = "date", name = "Date", defaultValue = "2010-05-18"),
- @Property(key = "datetime", name = "DateTime", defaultValue = "2010-05-18T15:50:45+0100"),
- @Property(key = "boolean", name = "Boolean", defaultValue = "true"),
- @Property(key = "falseboolean", name = "False Boolean", defaultValue = "false"),
- @Property(key = "integer", name = "Integer", defaultValue = "12345"),
- @Property(key = "array", name = "Array", defaultValue = "one,two,three"),
- @Property(key = "multi_values", name = "Array", defaultValue = "1,2,3", multiValues = true),
- @Property(key = "sonar.jira", name = "Jira Server", type = PropertyType.PROPERTY_SET, propertySetKey = "jira"),
- @Property(key = "newKey", name = "New key", deprecatedKey = "oldKey"),
- @Property(key = "newKeyWithDefaultValue", name = "New key with default value", deprecatedKey = "oldKeyWithDefaultValue", defaultValue = "default_value"),
- @Property(key = "new_multi_values", name = "New multi values", defaultValue = "1,2,3", multiValues = true, deprecatedKey = "old_multi_values")
- })
- private static class Init {
- }
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Before
- public void init_definitions() {
- definitions = new PropertyDefinitions();
- definitions.addComponent(Init.class);
- }
-
- @Test
- public void set_throws_NPE_if_key_is_null() {
- MapSettings underTest = new MapSettings();
-
- expectKeyNullNPE();
-
- underTest.set(null, randomAlphanumeric(3));
- }
-
- @Test
- public void set_throws_NPE_if_value_is_null() {
- MapSettings underTest = new MapSettings();
-
- expectedException.expect(NullPointerException.class);
- expectedException.expectMessage("value can't be null");
-
- underTest.set(randomAlphanumeric(3), null);
- }
-
- @Test
- public void set_accepts_empty_value_and_trims_it() {
- MapSettings underTest = new MapSettings();
- Random random = new Random();
- String key = randomAlphanumeric(3);
-
- underTest.set(key, blank(random));
-
- assertThat(underTest.getString(key)).isEmpty();
- }
-
- @Test
- public void default_values_should_be_loaded_from_definitions() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getDefaultValue("hello")).isEqualTo("world");
- }
-
- @Test
- @UseDataProvider("setPropertyCalls")
- public void all_setProperty_methods_throws_NPE_if_key_is_null(BiConsumer<Settings, String> setPropertyCaller) {
- Settings settings = new MapSettings();
-
- expectKeyNullNPE();
-
- setPropertyCaller.accept(settings, null);
- }
-
- @Test
- public void set_property_string_throws_NPE_if_key_is_null() {
- String key = randomAlphanumeric(3);
-
- Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
-
- expectKeyNullNPE();
-
- underTest.setProperty(null, new String[] {"1", "2"});
- }
-
- private void expectKeyNullNPE() {
- expectedException.expect(NullPointerException.class);
- expectedException.expectMessage("key can't be null");
- }
-
- @Test
- @UseDataProvider("setPropertyCalls")
- public void all_set_property_methods_trims_key(BiConsumer<Settings, String> setPropertyCaller) {
- Settings underTest = new MapSettings();
-
- Random random = new Random();
- String blankBefore = blank(random);
- String blankAfter = blank(random);
- String key = randomAlphanumeric(3);
-
- setPropertyCaller.accept(underTest, blankBefore + key + blankAfter);
-
- assertThat(underTest.hasKey(key)).isTrue();
- }
-
- @Test
- public void set_property_string_array_trims_key() {
- String key = randomAlphanumeric(3);
-
- Settings underTest = new MapSettings(new PropertyDefinitions(singletonList(PropertyDefinition.builder(key).multiValues(true).build())));
-
- Random random = new Random();
- String blankBefore = blank(random);
- String blankAfter = blank(random);
-
- underTest.setProperty(blankBefore + key + blankAfter, new String[] {"1", "2"});
-
- assertThat(underTest.hasKey(key)).isTrue();
- }
-
- private static String blank(Random random) {
- StringBuilder b = new StringBuilder();
- IntStream.range(0, random.nextInt(3)).mapToObj(s -> " ").forEach(b::append);
- return b.toString();
- }
-
- @DataProvider
- public static Object[][] setPropertyCalls() {
- List<BiConsumer<Settings, String>> callers = Arrays.asList(
- (settings, key) -> settings.setProperty(key, 123),
- (settings, key) -> settings.setProperty(key, 123L),
- (settings, key) -> settings.setProperty(key, 123.2F),
- (settings, key) -> settings.setProperty(key, 123.2D),
- (settings, key) -> settings.setProperty(key, false),
- (settings, key) -> settings.setProperty(key, new Date()),
- (settings, key) -> settings.setProperty(key, new Date(), true));
-
- return callers.stream().map(t -> new Object[] {t}).toArray(Object[][]::new);
- }
-
- @Test
- public void setProperty_methods_trims_value() {
- Settings underTest = new MapSettings();
-
- Random random = new Random();
- String blankBefore = blank(random);
- String blankAfter = blank(random);
- String key = randomAlphanumeric(3);
- String value = randomAlphanumeric(3);
-
- underTest.setProperty(key, blankBefore + value + blankAfter);
-
- assertThat(underTest.getString(key)).isEqualTo(value);
- }
-
- @Test
- public void set_property_int() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", 123);
- assertThat(settings.getInt("foo")).isEqualTo(123);
- assertThat(settings.getString("foo")).isEqualTo("123");
- assertThat(settings.getBoolean("foo")).isFalse();
- }
-
- @Test
- public void default_number_values_are_zero() {
- Settings settings = new MapSettings();
- assertThat(settings.getInt("foo")).isEqualTo(0);
- assertThat(settings.getLong("foo")).isEqualTo(0L);
- }
-
- @Test
- public void getInt_value_must_be_valid() {
- thrown.expect(NumberFormatException.class);
-
- Settings settings = new MapSettings();
- settings.setProperty("foo", "not a number");
- settings.getInt("foo");
- }
-
- @Test
- public void all_values_should_be_trimmed_set_property() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", " FOO ");
- assertThat(settings.getString("foo")).isEqualTo("FOO");
- }
-
- @Test
- public void test_get_default_value() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getDefaultValue("unknown")).isNull();
- }
-
- @Test
- public void test_get_string() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("hello", "Russia");
- assertThat(settings.getString("hello")).isEqualTo("Russia");
- }
-
- @Test
- public void setProperty_date() {
- Settings settings = new MapSettings();
- Date date = DateUtils.parseDateTime("2010-05-18T15:50:45+0100");
- settings.setProperty("aDate", date);
- settings.setProperty("aDateTime", date, true);
-
- assertThat(settings.getString("aDate")).isEqualTo("2010-05-18");
- assertThat(settings.getString("aDateTime")).startsWith("2010-05-18T");
- }
-
- @Test
- public void test_get_date() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getDate("unknown")).isNull();
- assertThat(settings.getDate("date").getDate()).isEqualTo(18);
- assertThat(settings.getDate("date").getMonth()).isEqualTo(4);
- }
-
- @Test
- public void test_get_date_not_found() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getDate("unknown")).isNull();
- }
-
- @Test
- public void test_get_datetime() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getDateTime("unknown")).isNull();
- assertThat(settings.getDateTime("datetime").getDate()).isEqualTo(18);
- assertThat(settings.getDateTime("datetime").getMonth()).isEqualTo(4);
- assertThat(settings.getDateTime("datetime").getMinutes()).isEqualTo(50);
- }
-
- @Test
- public void test_get_double() {
- Settings settings = new MapSettings();
- settings.setProperty("from_double", 3.14159);
- settings.setProperty("from_string", "3.14159");
- assertThat(settings.getDouble("from_double")).isEqualTo(3.14159, Offset.offset(0.00001));
- assertThat(settings.getDouble("from_string")).isEqualTo(3.14159, Offset.offset(0.00001));
- assertThat(settings.getDouble("unknown")).isNull();
- }
-
- @Test
- public void test_get_float() {
- Settings settings = new MapSettings();
- settings.setProperty("from_float", 3.14159f);
- settings.setProperty("from_string", "3.14159");
- assertThat(settings.getDouble("from_float")).isEqualTo(3.14159f, Offset.offset(0.00001));
- assertThat(settings.getDouble("from_string")).isEqualTo(3.14159f, Offset.offset(0.00001));
- assertThat(settings.getDouble("unknown")).isNull();
- }
-
- @Test
- public void test_get_bad_float() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "bar");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("The property 'foo' is not a float value");
- settings.getFloat("foo");
- }
-
- @Test
- public void test_get_bad_double() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "bar");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("The property 'foo' is not a double value");
- settings.getDouble("foo");
- }
-
- @Test
- public void testSetNullFloat() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", (Float) null);
- assertThat(settings.getFloat("foo")).isNull();
- }
-
- @Test
- public void testSetNullDouble() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", (Double) null);
- assertThat(settings.getDouble("foo")).isNull();
- }
-
- @Test
- public void getStringArray() {
- Settings settings = new MapSettings(definitions);
- String[] array = settings.getStringArray("array");
- assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
- }
-
- @Test
- public void setStringArray() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("multi_values", new String[] {"A", "B"});
- String[] array = settings.getStringArray("multi_values");
- assertThat(array).isEqualTo(new String[] {"A", "B"});
- }
-
- @Test
- public void setStringArrayTrimValues() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("multi_values", new String[] {" A ", " B "});
- String[] array = settings.getStringArray("multi_values");
- assertThat(array).isEqualTo(new String[] {"A", "B"});
- }
-
- @Test
- public void setStringArrayEscapeCommas() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("multi_values", new String[] {"A,B", "C,D"});
- String[] array = settings.getStringArray("multi_values");
- assertThat(array).isEqualTo(new String[] {"A,B", "C,D"});
- }
-
- @Test
- public void setStringArrayWithEmptyValues() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("multi_values", new String[] {"A,B", "", "C,D"});
- String[] array = settings.getStringArray("multi_values");
- assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
- }
-
- @Test
- public void setStringArrayWithNullValues() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("multi_values", new String[] {"A,B", null, "C,D"});
- String[] array = settings.getStringArray("multi_values");
- assertThat(array).isEqualTo(new String[] {"A,B", "", "C,D"});
- }
-
- @Test(expected = IllegalStateException.class)
- public void shouldFailToSetArrayValueOnSingleValueProperty() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("array", new String[] {"A", "B", "C"});
- }
-
- @Test
- public void getStringArray_no_value() {
- Settings settings = new MapSettings();
- String[] array = settings.getStringArray("array");
- assertThat(array).isEmpty();
- }
-
- @Test
- public void shouldTrimArray() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", " one, two, three ");
- String[] array = settings.getStringArray("foo");
- assertThat(array).isEqualTo(new String[] {"one", "two", "three"});
- }
-
- @Test
- public void shouldKeepEmptyValuesWhenSplitting() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", " one, , two");
- String[] array = settings.getStringArray("foo");
- assertThat(array).isEqualTo(new String[] {"one", "", "two"});
- }
-
- @Test
- public void testDefaultValueOfGetString() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getString("hello")).isEqualTo("world");
- }
-
- @Test
- public void set_property_boolean() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", true);
- settings.setProperty("bar", false);
- assertThat(settings.getBoolean("foo")).isTrue();
- assertThat(settings.getBoolean("bar")).isFalse();
- assertThat(settings.getString("foo")).isEqualTo("true");
- assertThat(settings.getString("bar")).isEqualTo("false");
- }
-
- @Test
- public void ignore_case_of_boolean_values() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "true");
- settings.setProperty("bar", "TRUE");
- // labels in UI
- settings.setProperty("baz", "True");
-
- assertThat(settings.getBoolean("foo")).isTrue();
- assertThat(settings.getBoolean("bar")).isTrue();
- assertThat(settings.getBoolean("baz")).isTrue();
- }
-
- @Test
- public void get_boolean() {
- Settings settings = new MapSettings(definitions);
- assertThat(settings.getBoolean("boolean")).isTrue();
- assertThat(settings.getBoolean("falseboolean")).isFalse();
- assertThat(settings.getBoolean("unknown")).isFalse();
- assertThat(settings.getBoolean("hello")).isFalse();
- }
-
- @Test
- public void shouldCreateByIntrospectingComponent() {
- Settings settings = new MapSettings();
- settings.getDefinitions().addComponent(MyComponent.class);
-
- // property definition has been loaded, ie for default value
- assertThat(settings.getDefaultValue("foo")).isEqualTo("bar");
- }
-
- @Property(key = "foo", name = "Foo", defaultValue = "bar")
- public static class MyComponent {
-
- }
-
- @Test
- public void getStringLines_no_value() {
- assertThat(new MapSettings().getStringLines("foo")).hasSize(0);
- }
-
- @Test
- public void getStringLines_single_line() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "the line");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"the line"});
- }
-
- @Test
- public void getStringLines_linux() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "one\ntwo");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
-
- settings.setProperty("foo", "one\ntwo\n");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
- }
-
- @Test
- public void getStringLines_windows() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "one\r\ntwo");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
-
- settings.setProperty("foo", "one\r\ntwo\r\n");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two"});
- }
-
- @Test
- public void getStringLines_mix() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "one\r\ntwo\nthree");
- assertThat(settings.getStringLines("foo")).isEqualTo(new String[] {"one", "two", "three"});
- }
-
- @Test
- public void getKeysStartingWith() {
- Settings settings = new MapSettings();
- settings.setProperty("sonar.jdbc.url", "foo");
- settings.setProperty("sonar.jdbc.username", "bar");
- settings.setProperty("sonar.security", "admin");
-
- assertThat(settings.getKeysStartingWith("sonar")).containsOnly("sonar.jdbc.url", "sonar.jdbc.username", "sonar.security");
- assertThat(settings.getKeysStartingWith("sonar.jdbc")).containsOnly("sonar.jdbc.url", "sonar.jdbc.username");
- assertThat(settings.getKeysStartingWith("other")).hasSize(0);
- }
-
- @Test
- public void should_fallback_deprecated_key_to_default_value_of_new_key() {
- Settings settings = new MapSettings(definitions);
-
- assertThat(settings.getString("newKeyWithDefaultValue")).isEqualTo("default_value");
- assertThat(settings.getString("oldKeyWithDefaultValue")).isEqualTo("default_value");
- }
-
- @Test
- public void should_fallback_deprecated_key_to_new_key() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("newKey", "value of newKey");
-
- assertThat(settings.getString("newKey")).isEqualTo("value of newKey");
- assertThat(settings.getString("oldKey")).isEqualTo("value of newKey");
- }
-
- @Test
- public void should_load_value_of_deprecated_key() {
- // it's used for example when deprecated settings are set through command-line
- Settings settings = new MapSettings(definitions);
- settings.setProperty("oldKey", "value of oldKey");
-
- assertThat(settings.getString("newKey")).isEqualTo("value of oldKey");
- assertThat(settings.getString("oldKey")).isEqualTo("value of oldKey");
- }
-
- @Test
- public void should_load_values_of_deprecated_key() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("oldKey", "a,b");
-
- assertThat(settings.getStringArray("newKey")).containsOnly("a", "b");
- assertThat(settings.getStringArray("oldKey")).containsOnly("a", "b");
- }
-
- @Test
- public void should_support_deprecated_props_with_multi_values() {
- Settings settings = new MapSettings(definitions);
- settings.setProperty("new_multi_values", new String[] {" A ", " B "});
- assertThat(settings.getStringArray("new_multi_values")).isEqualTo(new String[] {"A", "B"});
- assertThat(settings.getStringArray("old_multi_values")).isEqualTo(new String[] {"A", "B"});
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.config.internal;
-
-import com.tngtech.java.junit.dataprovider.DataProvider;
-import com.tngtech.java.junit.dataprovider.DataProviderRunner;
-import com.tngtech.java.junit.dataprovider.UseDataProvider;
-import java.util.Random;
-import java.util.function.Function;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
-import static org.sonar.api.config.internal.MultivalueProperty.trimFieldsAndRemoveEmptyFields;
-
-@RunWith(DataProviderRunner.class)
-public class MultivaluePropertyTest {
- private static final String[] EMPTY_STRING_ARRAY = {};
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- @UseDataProvider("testParseAsCsv")
- public void parseAsCsv_for_coverage(String value, String[] expected) {
- // parseAsCsv is extensively tested in org.sonar.server.config.ConfigurationProviderTest
- assertThat(parseAsCsv("key", value))
- .isEqualTo(parseAsCsv("key", value, Function.identity()))
- .isEqualTo(expected);
- }
-
- @Test
- public void parseAsCsv_fails_with_ISE_if_value_can_not_be_parsed() {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Property: 'multi' doesn't contain a valid CSV value: '\"a ,b'");
-
- parseAsCsv("multi", "\"a ,b");
- }
-
- @DataProvider
- public static Object[][] testParseAsCsv() {
- return new Object[][] {
- {"a", arrayOf("a")},
- {" a", arrayOf("a")},
- {"a ", arrayOf("a")},
- {" a, b", arrayOf("a", "b")},
- {"a,b ", arrayOf("a", "b")},
- {"a,,,b,c,,d", arrayOf("a", "b", "c", "d")},
- {" , \n ,, \t", EMPTY_STRING_ARRAY},
- {"\" a\"", arrayOf(" a")},
- {"\",\"", arrayOf(",")},
- // escaped quote in quoted field
- {"\"\"\"\"", arrayOf("\"")}
- };
- }
-
- private static String[] arrayOf(String... strs) {
- return strs;
- }
-
- @Test
- public void trimFieldsAndRemoveEmptyFields_throws_NPE_if_arg_is_null() {
- expectedException.expect(NullPointerException.class);
-
- trimFieldsAndRemoveEmptyFields(null);
- }
-
- @Test
- @UseDataProvider("plains")
- public void trimFieldsAndRemoveEmptyFields_ignores_EmptyFields(String str) {
- assertThat(trimFieldsAndRemoveEmptyFields("")).isEqualTo("");
- assertThat(trimFieldsAndRemoveEmptyFields(str)).isEqualTo(str);
-
- assertThat(trimFieldsAndRemoveEmptyFields(',' + str)).isEqualTo(str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ',')).isEqualTo(str);
- assertThat(trimFieldsAndRemoveEmptyFields(",,," + str)).isEqualTo(str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ",,,")).isEqualTo(str);
-
- assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str)).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str)).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str)).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields("," + str + ",,," + str)).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(",,," + str + ",,," + str)).isEqualTo(str + ',' + str);
-
- assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',')).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str + ",")).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ",,," + str + ",,")).isEqualTo(str + ',' + str);
-
- assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str + ',')).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(",," + str + ',' + str + ',')).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ",," + str + ',')).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(',' + str + ',' + str + ",,")).isEqualTo(str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(",,," + str + ",,," + str + ",,")).isEqualTo(str + ',' + str);
-
- assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',' + str)).isEqualTo(str + ',' + str + ',' + str);
- assertThat(trimFieldsAndRemoveEmptyFields(str + ',' + str + ',' + str)).isEqualTo(str + ',' + str + ',' + str);
- }
-
- @DataProvider
- public static Object[][] plains() {
- return new Object[][] {
- {randomAlphanumeric(1)},
- {randomAlphanumeric(2)},
- {randomAlphanumeric(3 + new Random().nextInt(5))}
- };
- }
-
- @Test
- @UseDataProvider("emptyAndtrimmable")
- public void trimFieldsAndRemoveEmptyFields_ignores_empty_fields_and_trims_fields(String empty, String trimmable) {
- String expected = trimmable.trim();
- assertThat(empty.trim()).isEmpty();
-
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + empty)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ",," + empty)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + trimmable)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ",," + trimmable)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + trimmable + ',' + empty)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ",," + trimmable + ",,," + empty)).isEqualTo(expected);
-
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + empty + ',' + empty)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ",," + empty + ",,," + empty)).isEqualTo(expected);
-
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ',' + empty + ',' + trimmable)).isEqualTo(expected);
- assertThat(trimFieldsAndRemoveEmptyFields(empty + ",,,," + empty + ",," + trimmable)).isEqualTo(expected);
-
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected);
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + ',' + trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected + ',' + expected);
- assertThat(trimFieldsAndRemoveEmptyFields(trimmable + "," + trimmable + ',' + trimmable)).isEqualTo(expected + ',' + expected + ',' + expected);
- }
-
- @Test
- public void trimAccordingToStringTrim() {
- String str = randomAlphanumeric(4);
- for (int i = 0; i <= ' '; i++) {
- String prefixed = (char) i + str;
- String suffixed = (char) i + str;
- String both = (char) i + str + (char) i;
- assertThat(trimFieldsAndRemoveEmptyFields(prefixed)).isEqualTo(prefixed.trim());
- assertThat(trimFieldsAndRemoveEmptyFields(suffixed)).isEqualTo(suffixed.trim());
- assertThat(trimFieldsAndRemoveEmptyFields(both)).isEqualTo(both.trim());
- }
- }
-
- @DataProvider
- public static Object[][] emptyAndtrimmable() {
- Random random = new Random();
- String oneEmpty = randomTrimmedChars(1, random);
- String twoEmpty = randomTrimmedChars(2, random);
- String threePlusEmpty = randomTrimmedChars(3 + random.nextInt(5), random);
- String onePlusEmpty = randomTrimmedChars(1 + random.nextInt(5), random);
-
- String plain = randomAlphanumeric(1);
- String plainWithtrimmable = randomAlphanumeric(2) + onePlusEmpty + randomAlphanumeric(3);
- String quotedWithSeparator = '"' + randomAlphanumeric(3) + ',' + randomAlphanumeric(2) + '"';
- String quotedWithDoubleSeparator = '"' + randomAlphanumeric(3) + ",," + randomAlphanumeric(2) + '"';
- String quotedWithtrimmable = '"' + randomAlphanumeric(3) + onePlusEmpty + randomAlphanumeric(2) + '"';
-
- String[] empties = {oneEmpty, twoEmpty, threePlusEmpty};
- String[] strings = {plain, plainWithtrimmable,
- onePlusEmpty + plain, plain + onePlusEmpty, onePlusEmpty + plain + onePlusEmpty,
- onePlusEmpty + plainWithtrimmable, plainWithtrimmable + onePlusEmpty, onePlusEmpty + plainWithtrimmable + onePlusEmpty,
- onePlusEmpty + quotedWithSeparator, quotedWithSeparator + onePlusEmpty, onePlusEmpty + quotedWithSeparator + onePlusEmpty,
- onePlusEmpty + quotedWithDoubleSeparator, quotedWithDoubleSeparator + onePlusEmpty, onePlusEmpty + quotedWithDoubleSeparator + onePlusEmpty,
- onePlusEmpty + quotedWithtrimmable, quotedWithtrimmable + onePlusEmpty, onePlusEmpty + quotedWithtrimmable + onePlusEmpty
- };
-
- Object[][] res = new Object[empties.length * strings.length][2];
- int i = 0;
- for (String empty : empties) {
- for (String string : strings) {
- res[i][0] = empty;
- res[i][1] = string;
- i++;
- }
- }
- return res;
- }
-
- @Test
- @UseDataProvider("emptys")
- public void trimFieldsAndRemoveEmptyFields_quotes_allow_to_preserve_fields(String empty) {
- String quotedEmpty = '"' + empty + '"';
-
- assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty)).isEqualTo(quotedEmpty);
- assertThat(trimFieldsAndRemoveEmptyFields(',' + quotedEmpty)).isEqualTo(quotedEmpty);
- assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',')).isEqualTo(quotedEmpty);
- assertThat(trimFieldsAndRemoveEmptyFields(',' + quotedEmpty + ',')).isEqualTo(quotedEmpty);
-
- assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',' + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty);
- assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ",," + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty);
-
- assertThat(trimFieldsAndRemoveEmptyFields(quotedEmpty + ',' + quotedEmpty + ',' + quotedEmpty)).isEqualTo(quotedEmpty + ',' + quotedEmpty + ',' + quotedEmpty);
- }
-
- @DataProvider
- public static Object[][] emptys() {
- Random random = new Random();
- return new Object[][] {
- {randomTrimmedChars(1, random)},
- {randomTrimmedChars(2, random)},
- {randomTrimmedChars(3 + random.nextInt(5), random)}
- };
- }
-
- @Test
- public void trimFieldsAndRemoveEmptyFields_supports_escaped_quote_in_quotes() {
- assertThat(trimFieldsAndRemoveEmptyFields("\"f\"\"oo\"")).isEqualTo("\"f\"\"oo\"");
- assertThat(trimFieldsAndRemoveEmptyFields("\"f\"\"oo\",\"bar\"\"\"")).isEqualTo("\"f\"\"oo\",\"bar\"\"\"");
- }
-
- @Test
- public void trimFieldsAndRemoveEmptyFields_does_not_fail_on_unbalanced_quotes() {
- assertThat(trimFieldsAndRemoveEmptyFields("\"")).isEqualTo("\"");
- assertThat(trimFieldsAndRemoveEmptyFields("\"foo")).isEqualTo("\"foo");
- assertThat(trimFieldsAndRemoveEmptyFields("foo\"")).isEqualTo("foo\"");
-
- assertThat(trimFieldsAndRemoveEmptyFields("\"foo\",\"")).isEqualTo("\"foo\",\"");
- assertThat(trimFieldsAndRemoveEmptyFields("\",\"foo\"")).isEqualTo("\",\"foo\"");
-
- assertThat(trimFieldsAndRemoveEmptyFields("\"foo\",\", ")).isEqualTo("\"foo\",\", ");
-
- assertThat(trimFieldsAndRemoveEmptyFields(" a ,,b , c, \"foo\",\" ")).isEqualTo("a,b,c,\"foo\",\" ");
- assertThat(trimFieldsAndRemoveEmptyFields("\" a ,,b , c, ")).isEqualTo("\" a ,,b , c, ");
- }
-
- private static final char[] SOME_PRINTABLE_TRIMMABLE_CHARS = {
- ' ', '\t', '\n', '\r'
- };
-
- /**
- * Result of randomTrimmedChars being used as arguments to JUnit test method through the DataProvider feature, they
- * are printed to surefire report. Some of those chars breaks the parsing of the surefire report during sonar analysis.
- * Therefor, we only use a subset of the trimmable chars.
- */
- private static String randomTrimmedChars(int length, Random random) {
- char[] chars = new char[length];
- for (int i = 0; i < chars.length; i++) {
- chars[i] = SOME_PRINTABLE_TRIMMABLE_CHARS[random.nextInt(SOME_PRINTABLE_TRIMMABLE_CHARS.length)];
- }
- return new String(chars);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.internal;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import org.sonar.api.SonarEdition;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.Version;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class MetadataLoaderTest {
- private System2 system = mock(System2.class);
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void load_version_from_file_in_classpath() {
- Version version = MetadataLoader.loadVersion(System2.INSTANCE);
- assertThat(version).isNotNull();
- assertThat(version.major()).isGreaterThanOrEqualTo(5);
- }
-
- @Test
- public void load_edition_from_file_in_classpath() {
- SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
- assertThat(edition).isNotNull();
- }
-
- @Test
- public void load_edition_defaults_to_community_if_file_not_found() throws MalformedURLException {
- when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURI().toURL());
- SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
- assertThat(edition).isEqualTo(SonarEdition.COMMUNITY);
- }
-
- @Test
- public void throw_ISE_if_edition_is_invalid() {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Invalid edition found in '/sonar-edition.txt': 'TRASH'");
-
- MetadataLoader.parseEdition("trash");
- }
-
- @Test
- public void throw_ISE_if_fail_to_load_version() throws Exception {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Can not load /sonar-api-version.txt from classpath");
-
- when(system.getResource(anyString())).thenReturn(new File("target/unknown").toURI().toURL());
- MetadataLoader.loadVersion(system);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.internal;
-
-import org.sonar.api.SonarEdition;
-import org.assertj.core.api.Assertions;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.SonarProduct;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.utils.Version;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SonarRuntimeImplTest {
-
- private static final Version A_VERSION = Version.parse("6.0");
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void sonarQube_environment() {
- SonarRuntime apiVersion = SonarRuntimeImpl.forSonarQube(A_VERSION, SonarQubeSide.SCANNER, SonarEdition.COMMUNITY);
- assertThat(apiVersion.getApiVersion()).isEqualTo(A_VERSION);
- assertThat(apiVersion.getProduct()).isEqualTo(SonarProduct.SONARQUBE);
- assertThat(apiVersion.getSonarQubeSide()).isEqualTo(SonarQubeSide.SCANNER);
- }
-
- @Test
- public void sonarLint_environment() {
- SonarRuntime apiVersion = SonarRuntimeImpl.forSonarLint(A_VERSION);
- assertThat(apiVersion.getApiVersion()).isEqualTo(A_VERSION);
- assertThat(apiVersion.getProduct()).isEqualTo(SonarProduct.SONARLINT);
- try {
- apiVersion.getSonarQubeSide();
- Assertions.fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).isInstanceOf(UnsupportedOperationException.class);
- }
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void sonarqube_requires_side() {
- SonarRuntimeImpl.forSonarQube(A_VERSION, null, null);
- }
-
-}
import java.util.Arrays;
import java.util.HashSet;
import org.junit.Test;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.issue.DefaultNoSonarFilter;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.issue.DefaultNoSonarFilter;
import static org.assertj.core.api.Assertions.assertThat;
*/
package org.sonar.api.rules;
-import org.junit.Assert;
-import org.junit.Test;
-import org.sonar.api.utils.SonarException;
-
import java.util.Arrays;
import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
assertThat(rule.getSeverity()).isEqualTo(RulePriority.MAJOR);
}
- @Test(expected = SonarException.class)
+ @Test(expected = IllegalStateException.class)
public void should_not_authorize_unkown_status() {
Rule.create().setStatus("Unknown");
}
import org.junit.Test;
import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RulesDefinition.NewRule;
import org.sonar.check.Priority;
-import org.sonar.server.rule.RuleDefinitionContext;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.sonar.api.i18n.RuleI18n;
-import org.sonar.server.rule.RuleDefinitionContext;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.log.LogTester;
-import org.sonar.server.rule.RuleDefinitionContext;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;
-import org.sonar.server.rule.RuleDefinitionContext;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.utils.ExceptionCauseMatcher.hasType;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.server.ws.internal.PartImpl;
-import org.sonar.api.server.ws.internal.ValidatingRequest;
+import org.sonar.api.impl.ws.PartImpl;
+import org.sonar.api.impl.ws.ValidatingRequest;
import org.sonar.api.utils.DateUtils;
import static com.google.common.base.Strings.repeat;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.server.ws.internal;
-
-import java.io.InputStream;
-import org.junit.Test;
-import org.sonar.api.server.ws.Request;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Mockito.mock;
-
-public class SimpleGetRequestTest {
-
- SimpleGetRequest underTest = new SimpleGetRequest();
-
- @Test
- public void method() {
- assertThat(underTest.method()).isEqualTo("GET");
-
- underTest.setParam("foo", "bar");
- assertThat(underTest.param("foo")).isEqualTo("bar");
- assertThat(underTest.param("unknown")).isNull();
- }
-
- @Test
- public void has_param() {
- assertThat(underTest.method()).isEqualTo("GET");
-
- underTest.setParam("foo", "bar");
- assertThat(underTest.hasParam("foo")).isTrue();
- assertThat(underTest.hasParam("unknown")).isFalse();
- }
-
- @Test
- public void get_part() {
- InputStream inputStream = mock(InputStream.class);
- underTest.setPart("key", inputStream, "filename");
-
- Request.Part part = underTest.paramAsPart("key");
- assertThat(part.getInputStream()).isEqualTo(inputStream);
- assertThat(part.getFileName()).isEqualTo("filename");
-
- assertThat(underTest.paramAsPart("unknown")).isNull();
- }
-
- @Test
- public void getMediaType() {
- underTest.setMediaType("JSON");
-
- assertThat(underTest.getMediaType()).isEqualTo("JSON");
- }
-
- @Test
- public void multiParam_with_one_element() {
- underTest.setParam("foo", "bar");
-
- assertThat(underTest.multiParam("foo")).containsExactly("bar");
- }
-
- @Test
- public void multiParam_without_any_element() {
- assertThat(underTest.multiParam("42")).isEmpty();
- }
-
- @Test
- public void getParams() {
- underTest
- .setParam("foo", "bar")
- .setParam("fee", "beer");
-
- assertThat(underTest.getParams()).containsOnly(
- entry("foo", new String[] {"bar"}),
- entry("fee", new String[] {"beer"}));
- }
-
- @Test
- public void header_returns_empty_if_header_is_not_present() {
- assertThat(underTest.header("foo")).isEmpty();
- }
-
- @Test
- public void header_returns_value_of_header_if_present() {
- underTest.setHeader("foo", "bar");
- assertThat(underTest.header("foo")).hasValue("bar");
- }
-
- @Test
- public void header_returns_empty_string_value_if_header_is_present_without_value() {
- underTest.setHeader("foo", "");
- assertThat(underTest.header("foo")).hasValue("");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import javax.annotation.Nullable;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class AlwaysIncreasingSystem2Test {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void default_constructor_makes_now_start_with_random_number_and_increase_returned_value_by_100_with_each_call() {
- AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2();
- verifyValuesReturnedByNow(underTest, null, 100);
- }
-
- @Test
- public void constructor_with_increment_makes_now_start_with_random_number_and_increase_returned_value_by_specified_value_with_each_call() {
- AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(663);
-
- verifyValuesReturnedByNow(underTest, null, 663);
- }
-
- @Test
- public void constructor_with_initial_value_and_increment_makes_now_start_with_specified_value_and_increase_returned_value_by_specified_value_with_each_call() {
- AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(777777L, 96);
-
- verifyValuesReturnedByNow(underTest, 777777L, 96);
- }
-
- @Test
- public void constructor_with_initial_value_and_increment_throws_IAE_if_initial_value_is_less_than_0() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Initial value must be >= 0");
-
- new AlwaysIncreasingSystem2(-1, 100);
- }
-
- @Test
- public void constructor_with_initial_value_and_increment_accepts_initial_value_0() {
- AlwaysIncreasingSystem2 underTest = new AlwaysIncreasingSystem2(0, 100);
-
- verifyValuesReturnedByNow(underTest, 0L, 100);
- }
-
- @Test
- public void constructor_with_initial_value_and_increment_throws_IAE_if_increment_is_0() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("increment must be > 0");
-
- new AlwaysIncreasingSystem2(10, 0);
- }
-
- @Test
- public void constructor_with_initial_value_and_increment_throws_IAE_if_increment_is_less_than_0() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("increment must be > 0");
-
- new AlwaysIncreasingSystem2(10, -66);
- }
-
- @Test
- public void constructor_with_increment_throws_IAE_if_increment_is_0() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("increment must be > 0");
-
- new AlwaysIncreasingSystem2(0);
- }
-
- @Test
- public void constructor_with_increment_throws_IAE_if_increment_is_less_than_0() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("increment must be > 0");
-
- new AlwaysIncreasingSystem2(-20);
- }
-
- private void verifyValuesReturnedByNow(AlwaysIncreasingSystem2 underTest, @Nullable Long initialValue, int increment) {
- long previousValue = -1;
- for (int i = 0; i < 333; i++) {
- if (previousValue == -1) {
- long now = underTest.now();
- if (initialValue != null) {
- assertThat(now).isEqualTo(initialValue);
- } else {
- assertThat(now).isGreaterThan(0);
- }
- previousValue = now;
- } else {
- long now = underTest.now();
- assertThat(now).isEqualTo(previousValue + increment);
- previousValue = now;
- }
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import java.io.File;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultTempFolderTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Test
- public void createTempFolderAndFile() throws Exception {
- File rootTempFolder = temp.newFolder();
- DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
- File dir = underTest.newDir();
- assertThat(dir).exists().isDirectory();
- File file = underTest.newFile();
- assertThat(file).exists().isFile();
-
- new TempFolderCleaner(underTest).stop();
- assertThat(rootTempFolder).doesNotExist();
- }
-
- @Test
- public void createTempFolderWithName() throws Exception {
- File rootTempFolder = temp.newFolder();
- DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
- File dir = underTest.newDir("sample");
- assertThat(dir).exists().isDirectory();
- assertThat(new File(rootTempFolder, "sample")).isEqualTo(dir);
-
- new TempFolderCleaner(underTest).stop();
- assertThat(rootTempFolder).doesNotExist();
- }
-
- @Test
- public void newDir_throws_ISE_if_name_is_not_valid() throws Exception {
- File rootTempFolder = temp.newFolder();
- DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
- String tooLong = "tooooolong";
- for (int i = 0; i < 50; i++) {
- tooLong += "tooooolong";
- }
-
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Failed to create temp directory");
-
- underTest.newDir(tooLong);
- }
-
- @Test
- public void newFile_throws_ISE_if_name_is_not_valid() throws Exception {
- File rootTempFolder = temp.newFolder();
- DefaultTempFolder underTest = new DefaultTempFolder(rootTempFolder);
- String tooLong = "tooooolong";
- for (int i = 0; i < 50; i++) {
- tooLong += "tooooolong";
- }
-
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Failed to create temp file");
-
- underTest.newFile(tooLong, ".txt");
- }
-
- @Test
- public void clean_deletes_non_empty_directory() throws Exception {
- File dir = temp.newFolder();
- FileUtils.touch(new File(dir, "foo.txt"));
-
- DefaultTempFolder underTest = new DefaultTempFolder(dir);
- underTest.clean();
-
- assertThat(dir).doesNotExist();
- }
-
- @Test
- public void clean_does_not_fail_if_directory_has_already_been_deleted() throws Exception {
- File dir = temp.newFolder();
-
- DefaultTempFolder underTest = new DefaultTempFolder(dir);
- underTest.clean();
- assertThat(dir).doesNotExist();
-
- // second call does not fail, nor log ERROR logs
- underTest.clean();
-
- assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import org.junit.Test;
-
-import java.io.File;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class JUnitTempFolderTest {
-
- @Test
- public void apply() throws Throwable {
- JUnitTempFolder temp = new JUnitTempFolder();
- temp.before();
- File dir1 = temp.newDir();
- assertThat(dir1).isDirectory().exists();
-
- File dir2 = temp.newDir("foo");
- assertThat(dir2).isDirectory().exists();
-
- File file1 = temp.newFile();
- assertThat(file1).isFile().exists();
-
- File file2 = temp.newFile("foo", "txt");
- assertThat(file2).isFile().exists();
-
- temp.after();
- assertThat(dir1).doesNotExist();
- assertThat(dir2).doesNotExist();
- assertThat(file1).doesNotExist();
- assertThat(file2).doesNotExist();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.api.utils.internal;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class WorkDurationTest {
-
- static final int HOURS_IN_DAY = 8;
-
- static final Long ONE_MINUTE = 1L;
- static final Long ONE_HOUR_IN_MINUTES = ONE_MINUTE * 60;
- static final Long ONE_DAY_IN_MINUTES = ONE_HOUR_IN_MINUTES * HOURS_IN_DAY;
-
- @Test
- public void create_from_days_hours_minutes() {
- WorkDuration workDuration = WorkDuration.create(1, 1, 1, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(1);
- assertThat(workDuration.hours()).isEqualTo(1);
- assertThat(workDuration.minutes()).isEqualTo(1);
- assertThat(workDuration.toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES + ONE_HOUR_IN_MINUTES + ONE_MINUTE);
- assertThat(workDuration.hoursInDay()).isEqualTo(HOURS_IN_DAY);
- }
-
- @Test
- public void create_from_value_and_unit() {
- WorkDuration result = WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY);
- assertThat(result.days()).isEqualTo(1);
- assertThat(result.hours()).isEqualTo(0);
- assertThat(result.minutes()).isEqualTo(0);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
- assertThat(result.toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES);
-
- assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_DAY_IN_MINUTES);
- assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_HOUR_IN_MINUTES);
- assertThat(WorkDuration.createFromValueAndUnit(1, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toMinutes()).isEqualTo(ONE_MINUTE);
- }
-
- @Test
- public void create_from_minutes() {
- WorkDuration workDuration = WorkDuration.createFromMinutes(ONE_MINUTE, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(0);
- assertThat(workDuration.hours()).isEqualTo(0);
- assertThat(workDuration.minutes()).isEqualTo(1);
-
- workDuration = WorkDuration.createFromMinutes(ONE_HOUR_IN_MINUTES, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(0);
- assertThat(workDuration.hours()).isEqualTo(1);
- assertThat(workDuration.minutes()).isEqualTo(0);
-
- workDuration = WorkDuration.createFromMinutes(ONE_DAY_IN_MINUTES, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(1);
- assertThat(workDuration.hours()).isEqualTo(0);
- assertThat(workDuration.minutes()).isEqualTo(0);
- }
-
- @Test
- public void create_from_working_long() {
- // 1 minute
- WorkDuration workDuration = WorkDuration.createFromLong(1L, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(0);
- assertThat(workDuration.hours()).isEqualTo(0);
- assertThat(workDuration.minutes()).isEqualTo(1);
-
- // 1 hour
- workDuration = WorkDuration.createFromLong(100L, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(0);
- assertThat(workDuration.hours()).isEqualTo(1);
- assertThat(workDuration.minutes()).isEqualTo(0);
-
- // 1 day
- workDuration = WorkDuration.createFromLong(10000L, HOURS_IN_DAY);
- assertThat(workDuration.days()).isEqualTo(1);
- assertThat(workDuration.hours()).isEqualTo(0);
- assertThat(workDuration.minutes()).isEqualTo(0);
- }
-
- @Test
- public void convert_to_seconds() {
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_MINUTE);
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_HOUR_IN_MINUTES);
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toMinutes()).isEqualTo(2L * ONE_DAY_IN_MINUTES);
- }
-
- @Test
- public void convert_to_working_days() {
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d / 60d / 8d);
- assertThat(WorkDuration.createFromValueAndUnit(240, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toWorkingDays()).isEqualTo(0.5);
- assertThat(WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(0.5);
- assertThat(WorkDuration.createFromValueAndUnit(8, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(1d);
- assertThat(WorkDuration.createFromValueAndUnit(16, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d);
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toWorkingDays()).isEqualTo(2d);
- }
-
- @Test
- public void convert_to_working_long() {
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).toLong()).isEqualTo(2l);
- assertThat(WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(400l);
- assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(10200l);
- assertThat(WorkDuration.createFromValueAndUnit(8, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).toLong()).isEqualTo(10000l);
- assertThat(WorkDuration.createFromValueAndUnit(2, WorkDuration.UNIT.DAYS, HOURS_IN_DAY).toLong()).isEqualTo(20000l);
- }
-
- @Test
- public void add() {
- // 4h + 5h = 1d 1h
- WorkDuration result = WorkDuration.createFromValueAndUnit(4, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).add(WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY));
- assertThat(result.days()).isEqualTo(1);
- assertThat(result.hours()).isEqualTo(1);
- assertThat(result.minutes()).isEqualTo(0);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
-
- // 40 m + 30m = 1h 10m
- result = WorkDuration.createFromValueAndUnit(40, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY));
- assertThat(result.days()).isEqualTo(0);
- assertThat(result.hours()).isEqualTo(1);
- assertThat(result.minutes()).isEqualTo(10);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
-
- // 10 m + 20m = 30m
- assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(
- WorkDuration.createFromValueAndUnit(20, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY)
- ).minutes()).isEqualTo(30);
-
- assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).add(null).minutes()).isEqualTo(10);
- }
-
- @Test
- public void subtract() {
- // 1d 1h - 5h = 4h
- WorkDuration result = WorkDuration.create(1, 1, 0, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY));
- assertThat(result.days()).isEqualTo(0);
- assertThat(result.hours()).isEqualTo(4);
- assertThat(result.minutes()).isEqualTo(0);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
-
- // 1h 10m - 30m = 40m
- result = WorkDuration.create(0, 1, 10, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY));
- assertThat(result.days()).isEqualTo(0);
- assertThat(result.hours()).isEqualTo(0);
- assertThat(result.minutes()).isEqualTo(40);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
-
- // 30m - 20m = 10m
- assertThat(WorkDuration.createFromValueAndUnit(30, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).subtract(WorkDuration.createFromValueAndUnit(20, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY))
- .minutes()).isEqualTo(10);
-
- assertThat(WorkDuration.createFromValueAndUnit(10, WorkDuration.UNIT.MINUTES, HOURS_IN_DAY).subtract(null).minutes()).isEqualTo(10);
- }
-
- @Test
- public void multiply() {
- // 5h * 2 = 1d 2h
- WorkDuration result = WorkDuration.createFromValueAndUnit(5, WorkDuration.UNIT.HOURS, HOURS_IN_DAY).multiply(2);
- assertThat(result.days()).isEqualTo(1);
- assertThat(result.hours()).isEqualTo(2);
- assertThat(result.minutes()).isEqualTo(0);
- assertThat(result.hoursInDay()).isEqualTo(HOURS_IN_DAY);
- }
-
- @Test
- public void test_equals_and_hashcode() throws Exception {
- WorkDuration duration = WorkDuration.createFromLong(28800, HOURS_IN_DAY);
- WorkDuration durationWithSameValue = WorkDuration.createFromLong(28800, HOURS_IN_DAY);
- WorkDuration durationWithDifferentValue = WorkDuration.createFromLong(14400, HOURS_IN_DAY);
-
- assertThat(duration).isEqualTo(duration);
- assertThat(durationWithSameValue).isEqualTo(duration);
- assertThat(durationWithDifferentValue).isNotEqualTo(duration);
- assertThat(duration).isNotEqualTo(null);
-
- assertThat(duration.hashCode()).isEqualTo(duration.hashCode());
- assertThat(durationWithSameValue.hashCode()).isEqualTo(duration.hashCode());
- assertThat(durationWithDifferentValue.hashCode()).isNotEqualTo(duration.hashCode());
- }
-
- @Test
- public void test_toString() throws Exception {
- assertThat(WorkDuration.createFromLong(28800, HOURS_IN_DAY).toString()).isNotNull();
- }
-}
compile project(':sonar-scanner-protocol')
compile project(':sonar-ws')
compile project(':sonar-duplications')
+ compile project(':sonar-plugin-api-impl')
runtime project(path: ':sonar-plugin-api', configuration: 'shadow')
compileOnly project(path: ':sonar-plugin-api')
testCompile 'org.mockito:mockito-core'
testCompile project(':plugins:sonar-xoo-plugin')
testCompile project(':sonar-plugin-api').sourceSets.test.output
- testCompile project(':server:sonar-server')
}
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.sensor.DefaultMeasure;
+import org.sonar.api.impl.sensor.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.FileLinesContext;
import org.sonar.api.utils.KeyValueFormat;
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.TempFolder;
-import org.sonar.api.utils.internal.DefaultTempFolder;
-import org.sonar.scanner.fs.DefaultInputProject;
public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
static final String TMP_NAME = ".sonartmp";
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.scanner.bootstrap;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsConnector;
+import org.sonarqube.ws.client.WsRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static java.lang.String.format;
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static org.sonar.api.utils.Preconditions.checkState;
+
+public class DefaultScannerWsClient implements ScannerWsClient {
+ private static final int MAX_ERROR_MSG_LEN = 128;
+ private static final Logger LOG = Loggers.get(DefaultScannerWsClient.class);
+
+ private final WsClient target;
+ private final boolean hasCredentials;
+ private final GlobalAnalysisMode globalMode;
+
+ public DefaultScannerWsClient(WsClient target, boolean hasCredentials, GlobalAnalysisMode globalMode) {
+ this.target = target;
+ this.hasCredentials = hasCredentials;
+ this.globalMode = globalMode;
+ }
+
+ /**
+ * If an exception is not thrown, the response needs to be closed by either calling close() directly, or closing the
+ * body content's stream/reader.
+ *
+ * @throws IllegalStateException if the request could not be executed due to a connectivity problem or timeout. Because networks can
+ * fail during an exchange, it is possible that the remote server accepted the request before the failure
+ * @throws MessageException if there was a problem with authentication or if a error message was parsed from the response.
+ * @throws HttpException if the response code is not in range [200..300). Consider using {@link #createErrorMessage(HttpException)} to create more relevant messages for the users.
+ */
+ public WsResponse call(WsRequest request) {
+ checkState(!globalMode.isMediumTest(), "No WS call should be made in medium test mode");
+ Profiler profiler = Profiler.createIfDebug(LOG).start();
+ WsResponse response = target.wsConnector().call(request);
+ profiler.stopDebug(format("%s %d %s", request.getMethod(), response.code(), response.requestUrl()));
+ failIfUnauthorized(response);
+ return response;
+ }
+
+ public String baseUrl() {
+ return target.wsConnector().baseUrl();
+ }
+
+ WsConnector wsConnector() {
+ return target.wsConnector();
+ }
+
+ private void failIfUnauthorized(WsResponse response) {
+ int code = response.code();
+ if (code == HTTP_UNAUTHORIZED) {
+ response.close();
+ if (hasCredentials) {
+ // credentials are not valid
+ throw MessageException.of(format("Not authorized. Please check the properties %s and %s.",
+ CoreProperties.LOGIN, CoreProperties.PASSWORD));
+ }
+ // not authenticated - see https://jira.sonarsource.com/browse/SONAR-4048
+ throw MessageException.of(format("Not authorized. Analyzing this project requires to be authenticated. " +
+ "Please provide the values of the properties %s and %s.", CoreProperties.LOGIN, CoreProperties.PASSWORD));
+
+ }
+ if (code == HTTP_FORBIDDEN) {
+ throw MessageException.of("You're not authorized to run analysis. Please contact the project administrator.");
+ }
+ if (code == HTTP_BAD_REQUEST) {
+ String jsonMsg = tryParseAsJsonError(response.content());
+ if (jsonMsg != null) {
+ throw MessageException.of(jsonMsg);
+ }
+ }
+
+ // if failed, throws an HttpException
+ response.failIfNotSuccessful();
+ }
+
+ /**
+ * Tries to form a short and relevant error message from the exception, to be displayed in the console.
+ */
+ public static String createErrorMessage(HttpException exception) {
+ String json = tryParseAsJsonError(exception.content());
+ if (json != null) {
+ return json;
+ }
+
+ String msg = "HTTP code " + exception.code();
+ if (isHtml(exception.content())) {
+ return msg;
+ }
+
+ return msg + ": " + StringUtils.left(exception.content(), MAX_ERROR_MSG_LEN);
+ }
+
+ @CheckForNull
+ private static String tryParseAsJsonError(String responseContent) {
+ try {
+ JsonParser parser = new JsonParser();
+ JsonObject obj = parser.parse(responseContent).getAsJsonObject();
+ JsonArray errors = obj.getAsJsonArray("errors");
+ List<String> errorMessages = new ArrayList<>();
+ for (JsonElement e : errors) {
+ errorMessages.add(e.getAsJsonObject().get("msg").getAsString());
+ }
+ return String.join(", ", errorMessages);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private static boolean isHtml(String responseContent) {
+ return StringUtils.stripToEmpty(responseContent).startsWith("<!DOCTYPE html>");
+ }
+}
import org.sonar.api.Plugin;
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;
-import org.sonar.api.internal.PluginContextImpl;
+import org.sonar.api.impl.context.PluginContextImpl;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarQubeVersion;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.context.MetadataLoader;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.UriReader;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
+import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TempFolder;
-import org.sonar.api.utils.internal.DefaultTempFolder;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
private static final String PACK200 = "pack200";
private static final String UNCOMPRESSED_MD5_HEADER = "Sonar-UncompressedMD5";
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
private final File cacheDir;
private final File tempDir;
- public PluginFiles(ScannerWsClient wsClient, Configuration configuration) {
+ public PluginFiles(DefaultScannerWsClient wsClient, Configuration configuration) {
this.wsClient = wsClient;
File home = locateHomeDir(configuration);
this.cacheDir = mkdir(new File(home, "cache"), "user cache");
private static final String PLUGINS_WS_URL = "api/plugins/installed";
private final PluginFiles pluginFiles;
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
- public ScannerPluginInstaller(PluginFiles pluginFiles, ScannerWsClient wsClient) {
+ public ScannerPluginInstaller(PluginFiles pluginFiles, DefaultScannerWsClient wsClient) {
this.pluginFiles = pluginFiles;
this.wsClient = wsClient;
}
*/
package org.sonar.scanner.bootstrap;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import java.util.ArrayList;
-import java.util.List;
-import javax.annotation.CheckForNull;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonarqube.ws.client.HttpException;
-import org.sonarqube.ws.client.WsClient;
-import org.sonarqube.ws.client.WsConnector;
import org.sonarqube.ws.client.WsRequest;
import org.sonarqube.ws.client.WsResponse;
-import static java.lang.String.format;
-import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
-import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
-import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+public interface ScannerWsClient {
+ WsResponse call(WsRequest request);
-public class ScannerWsClient {
- private static final int MAX_ERROR_MSG_LEN = 128;
- private static final Logger LOG = Loggers.get(ScannerWsClient.class);
+ String baseUrl();
- private final WsClient target;
- private final boolean hasCredentials;
- private final GlobalAnalysisMode globalMode;
- public ScannerWsClient(WsClient target, boolean hasCredentials, GlobalAnalysisMode globalMode) {
- this.target = target;
- this.hasCredentials = hasCredentials;
- this.globalMode = globalMode;
- }
-
- /**
- * If an exception is not thrown, the response needs to be closed by either calling close() directly, or closing the
- * body content's stream/reader.
- *
- * @throws IllegalStateException if the request could not be executed due to a connectivity problem or timeout. Because networks can
- * fail during an exchange, it is possible that the remote server accepted the request before the failure
- * @throws MessageException if there was a problem with authentication or if a error message was parsed from the response.
- * @throws HttpException if the response code is not in range [200..300). Consider using {@link #createErrorMessage(HttpException)} to create more relevant messages for the users.
- */
- public WsResponse call(WsRequest request) {
- Preconditions.checkState(!globalMode.isMediumTest(), "No WS call should be made in medium test mode");
- Profiler profiler = Profiler.createIfDebug(LOG).start();
- WsResponse response = target.wsConnector().call(request);
- profiler.stopDebug(format("%s %d %s", request.getMethod(), response.code(), response.requestUrl()));
- failIfUnauthorized(response);
- return response;
- }
-
- public String baseUrl() {
- return target.wsConnector().baseUrl();
- }
-
- @VisibleForTesting
- WsConnector wsConnector() {
- return target.wsConnector();
- }
-
- private void failIfUnauthorized(WsResponse response) {
- int code = response.code();
- if (code == HTTP_UNAUTHORIZED) {
- response.close();
- if (hasCredentials) {
- // credentials are not valid
- throw MessageException.of(format("Not authorized. Please check the properties %s and %s.",
- CoreProperties.LOGIN, CoreProperties.PASSWORD));
- }
- // not authenticated - see https://jira.sonarsource.com/browse/SONAR-4048
- throw MessageException.of(format("Not authorized. Analyzing this project requires to be authenticated. " +
- "Please provide the values of the properties %s and %s.", CoreProperties.LOGIN, CoreProperties.PASSWORD));
-
- }
- if (code == HTTP_FORBIDDEN) {
- throw MessageException.of("You're not authorized to run analysis. Please contact the project administrator.");
- }
- if (code == HTTP_BAD_REQUEST) {
- String jsonMsg = tryParseAsJsonError(response.content());
- if (jsonMsg != null) {
- throw MessageException.of(jsonMsg);
- }
- }
-
- // if failed, throws an HttpException
- response.failIfNotSuccessful();
- }
-
- /**
- * Tries to form a short and relevant error message from the exception, to be displayed in the console.
- */
- public static String createErrorMessage(HttpException exception) {
- String json = tryParseAsJsonError(exception.content());
- if (json != null) {
- return json;
- }
-
- String msg = "HTTP code " + exception.code();
- if (isHtml(exception.content())) {
- return msg;
- }
-
- return msg + ": " + StringUtils.left(exception.content(), MAX_ERROR_MSG_LEN);
- }
-
- @CheckForNull
- private static String tryParseAsJsonError(String responseContent) {
- try {
- JsonParser parser = new JsonParser();
- JsonObject obj = parser.parse(responseContent).getAsJsonObject();
- JsonArray errors = obj.getAsJsonArray("errors");
- List<String> errorMessages = new ArrayList<>();
- for (JsonElement e : errors) {
- errorMessages.add(e.getAsJsonObject().get("msg").getAsString());
- }
- return Joiner.on(", ").join(errorMessages);
- } catch (Exception e) {
- return null;
- }
- }
-
- private static boolean isHtml(String responseContent) {
- return StringUtils.stripToEmpty(responseContent).startsWith("<!DOCTYPE html>");
- }
}
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout";
static final int DEFAULT_READ_TIMEOUT_SEC = 60;
- private ScannerWsClient wsClient;
+ private DefaultScannerWsClient wsClient;
- public synchronized ScannerWsClient provide(final RawScannerProperties scannerProps,
+ public synchronized DefaultScannerWsClient provide(final RawScannerProperties scannerProps,
final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
if (wsClient == null) {
String url = defaultIfBlank(scannerProps.property("sonar.host.url"), CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE);
connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
}
- wsClient = new ScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
+ wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
}
return wsClient;
}
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.trim;
-import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+import static org.sonar.api.impl.config.MultivalueProperty.parseAsCsv;
@Immutable
public abstract class DefaultConfiguration implements Configuration {
import org.sonar.duplications.index.ClonePart;
import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputComponent;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputComponent;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Duplicate;
import org.sonar.scanner.protocol.output.ScannerReport.Duplication;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Configuration;
import org.sonar.duplications.block.BlockChunker;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
public class CpdSettings {
private final Configuration settings;
import org.sonar.duplications.statement.StatementChunker;
import org.sonar.duplications.token.TokenChunker;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
/**
* Special case for Java that use a dedicated block indexer.
import org.sonar.duplications.index.PackedMemoryCloneIndex;
import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.api.test.CoverageBlock;
import org.sonar.api.test.TestCase;
import org.sonar.api.test.Testable;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
public class DefaultCoverageBlock implements CoverageBlock {
import org.sonar.api.test.Testable;
import org.sonar.api.test.exception.CoverageAlreadyExistsException;
import org.sonar.api.test.exception.IllegalDurationException;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
public class DefaultTestCase implements MutableTestCase {
import org.sonar.api.test.CoverageBlock;
import org.sonar.api.test.MutableTestable;
import org.sonar.api.test.TestCase;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
public class DefaultTestable implements MutableTestable {
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.test.MutableTestPlan;
import org.sonar.scanner.deprecated.perspectives.PerspectiveBuilder;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
public class TestPlanBuilder extends PerspectiveBuilder<MutableTestPlan> {
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.test.MutableTestable;
import org.sonar.scanner.deprecated.perspectives.PerspectiveBuilder;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
public class TestableBuilder extends PerspectiveBuilder<MutableTestable> {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.SystemUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-@Immutable
-public abstract class AbstractProjectOrModule extends DefaultInputComponent {
- private static final Logger LOGGER = Loggers.get(AbstractProjectOrModule.class);
- private final Path baseDir;
- private final Path workDir;
- private final String name;
- private final String originalName;
- private final String description;
- private final String keyWithBranch;
- private final String branch;
- private final Map<String, String> properties;
-
- private final String key;
- private final ProjectDefinition definition;
- private final Charset encoding;
-
- public AbstractProjectOrModule(ProjectDefinition definition, int scannerComponentId) {
- super(scannerComponentId);
- this.baseDir = initBaseDir(definition);
- this.workDir = initWorkingDir(definition);
- this.name = definition.getName();
- this.originalName = definition.getOriginalName();
- this.description = definition.getDescription();
- this.keyWithBranch = definition.getKeyWithBranch();
- this.branch = definition.getBranch();
- this.properties = Collections.unmodifiableMap(new HashMap<>(definition.properties()));
-
- this.definition = definition;
- this.key = definition.getKey();
- this.encoding = initEncoding(definition);
- }
-
- private static Charset initEncoding(ProjectDefinition module) {
- String encodingStr = module.properties().get(CoreProperties.ENCODING_PROPERTY);
- Charset result;
- if (StringUtils.isNotEmpty(encodingStr)) {
- result = Charset.forName(StringUtils.trim(encodingStr));
- } else {
- result = Charset.defaultCharset();
- }
- return result;
- }
-
- private static Path initBaseDir(ProjectDefinition module) {
- Path result;
- try {
- result = module.getBaseDir().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS);
- } catch (IOException e) {
- throw new IllegalStateException("Unable to resolve module baseDir", e);
- }
- return result;
- }
-
- private static Path initWorkingDir(ProjectDefinition module) {
- File workingDirAsFile = module.getWorkDir();
- Path workingDir = workingDirAsFile.getAbsoluteFile().toPath().normalize();
- if (SystemUtils.IS_OS_WINDOWS) {
- try {
- Files.createDirectories(workingDir);
- Files.setAttribute(workingDir, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS);
- } catch (IOException e) {
- LOGGER.warn("Failed to set working directory hidden: {}", e.getMessage());
- }
- }
- return workingDir;
- }
-
- /**
- * Module key without branch
- */
- @Override
- public String key() {
- return key;
- }
-
- @Override
- public boolean isFile() {
- return false;
- }
-
- public ProjectDefinition definition() {
- return definition;
- }
-
- public Path getBaseDir() {
- return baseDir;
- }
-
- public Path getWorkDir() {
- return workDir;
- }
-
- public String getKeyWithBranch() {
- return keyWithBranch;
- }
-
- @CheckForNull
- public String getBranch() {
- return branch;
- }
-
- public Map<String, String> properties() {
- return properties;
- }
-
- @CheckForNull
- public String getOriginalName() {
- return originalName;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public Charset getEncoding() {
- return encoding;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.stream.StreamSupport;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FilePredicates;
-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.scan.filesystem.PathResolver;
-import org.sonar.api.utils.PathUtils;
-import org.sonar.scanner.fs.predicates.DefaultFilePredicates;
-import org.sonar.scanner.fs.predicates.FileExtensionPredicate;
-import org.sonar.scanner.fs.predicates.OptimizedFilePredicateAdapter;
-
-/**
- * @since 4.2
- */
-public class DefaultFileSystem implements FileSystem {
-
- private final Cache cache;
- private final Path baseDir;
- private Path workDir;
- private Charset encoding;
- protected final FilePredicates predicates;
-
- /**
- * Only for testing
- */
- public DefaultFileSystem(Path baseDir) {
- this(baseDir, new MapCache());
- }
-
- /**
- * Only for testing
- */
- public DefaultFileSystem(File baseDir) {
- this(baseDir.toPath(), new MapCache());
- }
-
- protected DefaultFileSystem(Path baseDir, Cache cache) {
- this.baseDir = baseDir;
- this.cache = cache;
- this.predicates = new DefaultFilePredicates(this.baseDir);
- }
-
- public Path baseDirPath() {
- return baseDir;
- }
-
- @Override
- public File baseDir() {
- return baseDir.toFile();
- }
-
- public DefaultFileSystem setEncoding(Charset e) {
- this.encoding = e;
- return this;
- }
-
- @Override
- public Charset encoding() {
- return encoding;
- }
-
- public DefaultFileSystem setWorkDir(Path d) {
- this.workDir = d;
- return this;
- }
-
- @Override
- public File workDir() {
- return workDir.toFile();
- }
-
- @Override
- public InputFile inputFile(FilePredicate predicate) {
- Iterable<InputFile> files = inputFiles(predicate);
- Iterator<InputFile> iterator = files.iterator();
- if (!iterator.hasNext()) {
- return null;
- }
- InputFile first = iterator.next();
- if (!iterator.hasNext()) {
- return first;
- }
-
- StringBuilder sb = new StringBuilder();
- sb.append("expected one element but was: <" + first);
- for (int i = 0; i < 4 && iterator.hasNext(); i++) {
- sb.append(", " + iterator.next());
- }
- if (iterator.hasNext()) {
- sb.append(", ...");
- }
- sb.append('>');
-
- throw new IllegalArgumentException(sb.toString());
-
- }
-
- public Iterable<InputFile> inputFiles() {
- return inputFiles(predicates.all());
- }
-
- @Override
- public Iterable<InputFile> inputFiles(FilePredicate predicate) {
- return OptimizedFilePredicateAdapter.create(predicate).get(cache);
- }
-
- @Override
- public boolean hasFiles(FilePredicate predicate) {
- return inputFiles(predicate).iterator().hasNext();
- }
-
- @Override
- public Iterable<File> files(FilePredicate predicate) {
- return () -> StreamSupport.stream(inputFiles(predicate).spliterator(), false)
- .map(InputFile::file)
- .iterator();
- }
-
- @Override
- public InputDir inputDir(File dir) {
- String relativePath = PathUtils.sanitize(new PathResolver().relativePath(baseDir.toFile(), dir));
- if (relativePath == null) {
- return null;
- }
- // Issues on InputDir are moved to the project, so we just return a fake InputDir for backward compatibility
- return new DefaultInputDir("unused", relativePath).setModuleBaseDir(baseDir);
- }
-
- public DefaultFileSystem add(InputFile inputFile) {
- cache.add(inputFile);
- return this;
- }
-
- @Override
- public SortedSet<String> languages() {
- return cache.languages();
- }
-
- @Override
- public FilePredicates predicates() {
- return predicates;
- }
-
- public abstract static class Cache implements Index {
-
- protected abstract void doAdd(InputFile inputFile);
-
- final void add(InputFile inputFile) {
- doAdd(inputFile);
- }
-
- protected abstract SortedSet<String> languages();
- }
-
- /**
- * Used only for testing
- */
- private static class MapCache extends Cache {
- private final Map<String, InputFile> fileMap = new HashMap<>();
- private final Map<String, Set<InputFile>> filesByNameCache = new HashMap<>();
- private final Map<String, Set<InputFile>> filesByExtensionCache = new HashMap<>();
- private SortedSet<String> languages = new TreeSet<>();
-
- @Override
- public Iterable<InputFile> inputFiles() {
- return new ArrayList<>(fileMap.values());
- }
-
- @Override
- public InputFile inputFile(String relativePath) {
- return fileMap.get(relativePath);
- }
-
- @Override
- public Iterable<InputFile> getFilesByName(String filename) {
- return filesByNameCache.get(filename);
- }
-
- @Override
- public Iterable<InputFile> getFilesByExtension(String extension) {
- return filesByExtensionCache.get(extension);
- }
-
- @Override
- protected void doAdd(InputFile inputFile) {
- if (inputFile.language() != null) {
- languages.add(inputFile.language());
- }
- fileMap.put(inputFile.relativePath(), inputFile);
- filesByNameCache.computeIfAbsent(inputFile.filename(), x -> new HashSet<>()).add(inputFile);
- filesByExtensionCache.computeIfAbsent(FileExtensionPredicate.getExtension(inputFile), x -> new HashSet<>()).add(inputFile);
- }
-
- @Override
- protected SortedSet<String> languages() {
- return languages;
- }
- }
-
- @Override
- public File resolvePath(String path) {
- File file = new File(path);
- if (!file.isAbsolute()) {
- try {
- file = new File(baseDir(), path).getCanonicalFile();
- } catch (IOException e) {
- throw new IllegalArgumentException("Unable to resolve path '" + path + "'", e);
- }
- }
- return file;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.fs.IndexedFile;
-import org.sonar.api.batch.fs.InputFile.Type;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.api.utils.PathUtils;
-
-/**
- * @since 6.3
- */
-@Immutable
-public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile {
- private static AtomicInteger intGenerator = new AtomicInteger(0);
-
- private final String projectRelativePath;
- private final String moduleRelativePath;
- private final String projectKey;
- private final String language;
- private final Type type;
- private final Path absolutePath;
- private final SensorStrategy sensorStrategy;
-
- /**
- * Testing purposes only!
- */
- public DefaultIndexedFile(String projectKey, Path baseDir, String relativePath, @Nullable String language) {
- this(baseDir.resolve(relativePath), projectKey, relativePath, relativePath, Type.MAIN, language, intGenerator.getAndIncrement(),
- new SensorStrategy());
- }
-
- public DefaultIndexedFile(Path absolutePath, String projectKey, String projectRelativePath, String moduleRelativePath, Type type, @Nullable String language, int batchId,
- SensorStrategy sensorStrategy) {
- super(batchId);
- this.projectKey = projectKey;
- this.projectRelativePath = PathUtils.sanitize(projectRelativePath);
- this.moduleRelativePath = PathUtils.sanitize(moduleRelativePath);
- this.type = type;
- this.language = language;
- this.sensorStrategy = sensorStrategy;
- this.absolutePath = absolutePath;
- }
-
- @Override
- public String relativePath() {
- return sensorStrategy.isGlobal() ? projectRelativePath : moduleRelativePath;
- }
-
- public String getModuleRelativePath() {
- return moduleRelativePath;
- }
-
- public String getProjectRelativePath() {
- return projectRelativePath;
- }
-
- @Override
- public String absolutePath() {
- return PathUtils.sanitize(path().toString());
- }
-
- @Override
- public File file() {
- return path().toFile();
- }
-
- @Override
- public Path path() {
- return absolutePath;
- }
-
- @Override
- public InputStream inputStream() throws IOException {
- return Files.newInputStream(path());
- }
-
- @CheckForNull
- @Override
- public String language() {
- return language;
- }
-
- @Override
- public Type type() {
- return type;
- }
-
- /**
- * Component key (without branch).
- */
- @Override
- public String key() {
- return new StringBuilder().append(projectKey).append(":").append(projectRelativePath).toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (!(o instanceof DefaultIndexedFile)) {
- return false;
- }
-
- DefaultIndexedFile that = (DefaultIndexedFile) o;
- return projectRelativePath.equals(that.projectRelativePath);
- }
-
- @Override
- public int hashCode() {
- return projectRelativePath.hashCode();
- }
-
- @Override
- public String toString() {
- return projectRelativePath;
- }
-
- @Override
- public boolean isFile() {
- return true;
- }
-
- @Override
- public String filename() {
- return path().getFileName().toString();
- }
-
- @Override
- public URI uri() {
- return path().toUri();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.util.HashSet;
-import java.util.Set;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.measure.Metric;
-
-/**
- * @since 5.2
- */
-public abstract class DefaultInputComponent implements InputComponent {
- private int id;
- private Set<String> storedMetricKeys = new HashSet<>();
-
- public DefaultInputComponent(int scannerId) {
- this.id = scannerId;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || this.getClass() != o.getClass()) {
- return false;
- }
-
- DefaultInputComponent that = (DefaultInputComponent) o;
- return key().equals(that.key());
- }
-
- public int scannerId() {
- return id;
- }
-
- @Override
- public int hashCode() {
- return key().hashCode();
- }
-
- @Override
- public String toString() {
- return "[key=" + key() + "]";
- }
-
- public void setHasMeasureFor(Metric metric) {
- storedMetricKeys.add(metric.key());
- }
-
- public boolean hasMeasureFor(Metric metric) {
- return storedMetricKeys.contains(metric.key());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.net.URI;
-import java.nio.file.Path;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.fs.InputDir;
-import org.sonar.api.utils.PathUtils;
-
-/**
- * @since 4.5
- */
-public class DefaultInputDir extends DefaultInputComponent implements InputDir {
-
- private final String relativePath;
- private final String moduleKey;
- private Path moduleBaseDir;
-
- public DefaultInputDir(String moduleKey, String relativePath) {
- super(-1);
- this.moduleKey = moduleKey;
- this.relativePath = PathUtils.sanitize(relativePath);
- }
-
- @Override
- public String relativePath() {
- return relativePath;
- }
-
- @Override
- public String absolutePath() {
- return PathUtils.sanitize(path().toString());
- }
-
- @Override
- public File file() {
- return path().toFile();
- }
-
- @Override
- public Path path() {
- if (moduleBaseDir == null) {
- throw new IllegalStateException("Can not return the java.nio.file.Path because module baseDir is not set (see method setModuleBaseDir(java.io.File))");
- }
- return moduleBaseDir.resolve(relativePath);
- }
-
- public String moduleKey() {
- return moduleKey;
- }
-
- @Override
- public String key() {
- StringBuilder sb = new StringBuilder().append(moduleKey).append(":");
- if (StringUtils.isEmpty(relativePath)) {
- sb.append("/");
- } else {
- sb.append(relativePath);
- }
- return sb.toString();
- }
-
- /**
- * For testing purpose. Will be automatically set when dir is added to {@link DefaultFileSystem}
- */
- public DefaultInputDir setModuleBaseDir(Path moduleBaseDir) {
- this.moduleBaseDir = moduleBaseDir.normalize();
- return this;
- }
-
- @Override
- public boolean isFile() {
- return false;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || this.getClass() != o.getClass()) {
- return false;
- }
-
- DefaultInputDir that = (DefaultInputDir) o;
- return moduleKey.equals(that.moduleKey) && relativePath.equals(that.relativePath);
- }
-
- @Override
- public int hashCode() {
- return moduleKey.hashCode() + relativePath.hashCode() * 13;
- }
-
- @Override
- public String toString() {
- return "[moduleKey=" + moduleKey + ", relative=" + relativePath + ", basedir=" + moduleBaseDir + "]";
- }
-
- @Override
- public URI uri() {
- return path().toUri();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.Collection;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.io.ByteOrderMark;
-import org.apache.commons.io.input.BOMInputStream;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextPointer;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.fs.internal.Metadata;
-
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-/**
- * @since 4.2
- * To create {@link InputFile} in tests, use TestInputFileBuilder.
- */
-public class DefaultInputFile extends DefaultInputComponent implements InputFile {
-
- private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
- private final DefaultIndexedFile indexedFile;
- private final String contents;
- private final Consumer<DefaultInputFile> metadataGenerator;
-
- private boolean published;
- private boolean excludedForCoverage;
- private boolean excludedForDuplication;
- private boolean ignoreAllIssues;
- // Lazy init to save memory
- private BitSet noSonarLines;
- private Status status;
- private Charset charset;
- private Metadata metadata;
- private Collection<int[]> ignoreIssuesOnlineRanges;
- private BitSet executableLines;
-
- public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) {
- this(indexedFile, metadataGenerator, null);
- }
-
- // For testing
- public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator, @Nullable String contents) {
- super(indexedFile.scannerId());
- this.indexedFile = indexedFile;
- this.metadataGenerator = metadataGenerator;
- this.metadata = null;
- this.published = false;
- this.excludedForCoverage = false;
- this.contents = contents;
- }
-
- public void checkMetadata() {
- if (metadata == null) {
- metadataGenerator.accept(this);
- }
- }
-
- @Override
- public InputStream inputStream() throws IOException {
- return contents != null ? new ByteArrayInputStream(contents.getBytes(charset()))
- : new BOMInputStream(Files.newInputStream(path()),
- ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
- }
-
- @Override
- public String contents() throws IOException {
- if (contents != null) {
- return contents;
- } else {
- ByteArrayOutputStream result = new ByteArrayOutputStream();
- try (InputStream inputStream = inputStream()) {
- byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
- int length;
- while ((length = inputStream.read(buffer)) != -1) {
- result.write(buffer, 0, length);
- }
- }
- return result.toString(charset().name());
- }
- }
-
- public DefaultInputFile setPublished(boolean published) {
- this.published = published;
- return this;
- }
-
- public boolean isPublished() {
- return published;
- }
-
- public DefaultInputFile setExcludedForCoverage(boolean excludedForCoverage) {
- this.excludedForCoverage = excludedForCoverage;
- return this;
- }
-
- public boolean isExcludedForCoverage() {
- return excludedForCoverage;
- }
-
- public DefaultInputFile setExcludedForDuplication(boolean excludedForDuplication) {
- this.excludedForDuplication = excludedForDuplication;
- return this;
- }
-
- public boolean isExcludedForDuplication() {
- return excludedForDuplication;
- }
-
- /**
- * @deprecated since 6.6
- */
- @Deprecated
- @Override
- public String relativePath() {
- return indexedFile.relativePath();
- }
-
- public String getModuleRelativePath() {
- return indexedFile.getModuleRelativePath();
- }
-
- public String getProjectRelativePath() {
- return indexedFile.getProjectRelativePath();
- }
-
- @Override
- public String absolutePath() {
- return indexedFile.absolutePath();
- }
-
- @Override
- public File file() {
- return indexedFile.file();
- }
-
- @Override
- public Path path() {
- return indexedFile.path();
- }
-
- @CheckForNull
- @Override
- public String language() {
- return indexedFile.language();
- }
-
- @Override
- public Type type() {
- return indexedFile.type();
- }
-
- /**
- * Component key (without branch).
- */
- @Override
- public String key() {
- return indexedFile.key();
- }
-
- @Override
- public int hashCode() {
- return indexedFile.hashCode();
- }
-
- @Override
- public String toString() {
- return indexedFile.toString();
- }
-
- /**
- * {@link #setStatus(Status)}
- */
- @Override
- public Status status() {
- checkMetadata();
- return status;
- }
-
- @Override
- public int lines() {
- checkMetadata();
- return metadata.lines();
- }
-
- @Override
- public boolean isEmpty() {
- checkMetadata();
- return metadata.isEmpty();
- }
-
- @Override
- public Charset charset() {
- checkMetadata();
- return charset;
- }
-
- public int lastValidOffset() {
- checkMetadata();
- return metadata.lastValidOffset();
- }
-
- /**
- * Digest hash of the file.
- */
- public String hash() {
- checkMetadata();
- return metadata.hash();
- }
-
- public int nonBlankLines() {
- checkMetadata();
- return metadata.nonBlankLines();
- }
-
- public int[] originalLineStartOffsets() {
- checkMetadata();
- checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized.");
- checkState(metadata.originalLineStartOffsets().length == metadata.lines(),
- "InputFile is not properly initialized. 'originalLineStartOffsets' property length should be equal to 'lines'");
- return metadata.originalLineStartOffsets();
- }
-
- public int[] originalLineEndOffsets() {
- checkMetadata();
- checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized.");
- checkState(metadata.originalLineEndOffsets().length == metadata.lines(),
- "InputFile is not properly initialized. 'originalLineEndOffsets' property length should be equal to 'lines'");
- return metadata.originalLineEndOffsets();
- }
-
- @Override
- public TextPointer newPointer(int line, int lineOffset) {
- checkMetadata();
- DefaultTextPointer textPointer = new DefaultTextPointer(line, lineOffset);
- checkValid(textPointer, "pointer");
- return textPointer;
- }
-
- @Override
- public TextRange newRange(TextPointer start, TextPointer end) {
- checkMetadata();
- checkValid(start, "start pointer");
- checkValid(end, "end pointer");
- return newRangeValidPointers(start, end, false);
- }
-
- @Override
- public TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset) {
- checkMetadata();
- TextPointer start = newPointer(startLine, startLineOffset);
- TextPointer end = newPointer(endLine, endLineOffset);
- return newRangeValidPointers(start, end, false);
- }
-
- @Override
- public TextRange selectLine(int line) {
- checkMetadata();
- TextPointer startPointer = newPointer(line, 0);
- TextPointer endPointer = newPointer(line, lineLength(line));
- return newRangeValidPointers(startPointer, endPointer, true);
- }
-
- public void validate(TextRange range) {
- checkMetadata();
- checkValid(range.start(), "start pointer");
- checkValid(range.end(), "end pointer");
- }
-
- /**
- * Create Range from global offsets. Used for backward compatibility with older API.
- */
- public TextRange newRange(int startOffset, int endOffset) {
- checkMetadata();
- return newRangeValidPointers(newPointer(startOffset), newPointer(endOffset), false);
- }
-
- public TextPointer newPointer(int globalOffset) {
- checkMetadata();
- checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset);
- checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset());
- int line = findLine(globalOffset);
- int startLineOffset = originalLineStartOffsets()[line - 1];
- // In case the global offset is between \r and \n, move the pointer to a valid location
- return new DefaultTextPointer(line, Math.min(globalOffset, originalLineEndOffsets()[line - 1]) - startLineOffset);
- }
-
- public DefaultInputFile setStatus(Status status) {
- this.status = status;
- return this;
- }
-
- public DefaultInputFile setCharset(Charset charset) {
- this.charset = charset;
- return this;
- }
-
- private void checkValid(TextPointer pointer, String owner) {
- checkArgument(pointer.line() >= 1, "%s is not a valid line for a file", pointer.line());
- checkArgument(pointer.line() <= this.metadata.lines(), "%s is not a valid line for %s. File %s has %s line(s)", pointer.line(), owner, this, metadata.lines());
- checkArgument(pointer.lineOffset() >= 0, "%s is not a valid line offset for a file", pointer.lineOffset());
- int lineLength = lineLength(pointer.line());
- checkArgument(pointer.lineOffset() <= lineLength,
- "%s is not a valid line offset for %s. File %s has %s character(s) at line %s", pointer.lineOffset(), owner, this, lineLength, pointer.line());
- }
-
- private int lineLength(int line) {
- return originalLineEndOffsets()[line - 1] - originalLineStartOffsets()[line - 1];
- }
-
- private static TextRange newRangeValidPointers(TextPointer start, TextPointer end, boolean acceptEmptyRange) {
- checkArgument(acceptEmptyRange ? (start.compareTo(end) <= 0) : (start.compareTo(end) < 0),
- "Start pointer %s should be before end pointer %s", start, end);
- return new DefaultTextRange(start, end);
- }
-
- private int findLine(int globalOffset) {
- return Math.abs(Arrays.binarySearch(originalLineStartOffsets(), globalOffset) + 1);
- }
-
- public DefaultInputFile setMetadata(Metadata metadata) {
- this.metadata = metadata;
- return this;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
-
- if (this.getClass() != obj.getClass()) {
- return false;
- }
-
- DefaultInputFile that = (DefaultInputFile) obj;
- return this.getProjectRelativePath().equals(that.getProjectRelativePath());
- }
-
- @Override
- public boolean isFile() {
- return true;
- }
-
- @Override
- public String filename() {
- return indexedFile.filename();
- }
-
- @Override
- public URI uri() {
- return indexedFile.uri();
- }
-
- public void noSonarAt(Set<Integer> noSonarLines) {
- if (this.noSonarLines == null) {
- this.noSonarLines = new BitSet(lines());
- }
- noSonarLines.forEach(l -> this.noSonarLines.set(l - 1));
- }
-
- public boolean hasNoSonarAt(int line) {
- if (this.noSonarLines == null) {
- return false;
- }
- return this.noSonarLines.get(line - 1);
- }
-
- public boolean isIgnoreAllIssues() {
- return ignoreAllIssues;
- }
-
- public void setIgnoreAllIssues(boolean ignoreAllIssues) {
- this.ignoreAllIssues = ignoreAllIssues;
- }
-
- public void addIgnoreIssuesOnLineRanges(Collection<int[]> lineRanges) {
- if (this.ignoreIssuesOnlineRanges == null) {
- this.ignoreIssuesOnlineRanges = new ArrayList<>();
- }
- this.ignoreIssuesOnlineRanges.addAll(lineRanges);
- }
-
- public boolean isIgnoreAllIssuesOnLine(@Nullable Integer line) {
- if (line == null || ignoreIssuesOnlineRanges == null) {
- return false;
- }
- return ignoreIssuesOnlineRanges.stream().anyMatch(r -> r[0] <= line && line <= r[1]);
- }
-
- public void setExecutableLines(Set<Integer> executableLines) {
- checkState(this.executableLines == null, "Executable lines have already been saved for file: {}", this.toString());
- this.executableLines = new BitSet(lines());
- executableLines.forEach(l -> this.executableLines.set(l - 1));
- }
-
- public Optional<Set<Integer>> getExecutableLines() {
- if (this.executableLines == null) {
- return Optional.empty();
- }
- return Optional.of(this.executableLines.stream().map(i -> i + 1).boxed().collect(Collectors.toSet()));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputModule;
-import org.sonar.api.scan.filesystem.PathResolver;
-
-import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
-
-@Immutable
-public class DefaultInputModule extends AbstractProjectOrModule implements InputModule {
-
- private final List<Path> sourceDirsOrFiles;
- private final List<Path> testDirsOrFiles;
-
- /**
- * For testing only!
- */
- public DefaultInputModule(ProjectDefinition definition) {
- this(definition, 0);
- }
-
- public DefaultInputModule(ProjectDefinition definition, int scannerComponentId) {
- super(definition, scannerComponentId);
-
- this.sourceDirsOrFiles = initSources(definition, ProjectDefinition.SOURCES_PROPERTY);
- this.testDirsOrFiles = initSources(definition, ProjectDefinition.TESTS_PROPERTY);
- }
-
- @CheckForNull
- private List<Path> initSources(ProjectDefinition module, String propertyKey) {
- if (!module.properties().containsKey(propertyKey)) {
- return null;
- }
- List<Path> result = new ArrayList<>();
- PathResolver pathResolver = new PathResolver();
- String srcPropValue = module.properties().get(propertyKey);
- if (srcPropValue != null) {
- for (String sourcePath : parseAsCsv(propertyKey, srcPropValue)) {
- File dirOrFile = pathResolver.relativeFile(getBaseDir().toFile(), sourcePath);
- if (dirOrFile.exists()) {
- result.add(dirOrFile.toPath());
- }
- }
- }
- return result;
- }
-
- public Optional<List<Path>> getSourceDirsOrFiles() {
- return Optional.ofNullable(sourceDirsOrFiles);
- }
-
- public Optional<List<Path>> getTestDirsOrFiles() {
- return Optional.ofNullable(testDirsOrFiles);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.scanner.fs.InputProject;
-
-@Immutable
-public class DefaultInputProject extends AbstractProjectOrModule implements InputProject {
-
- /**
- * For testing only!
- */
- public DefaultInputProject(ProjectDefinition definition) {
- super(definition, 0);
- }
-
- public DefaultInputProject(ProjectDefinition definition, int scannerComponentId) {
- super(definition, scannerComponentId);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import org.sonar.api.batch.fs.TextPointer;
-
-/**
- * @since 5.2
- */
-public class DefaultTextPointer implements TextPointer {
-
- private final int line;
- private final int lineOffset;
-
- public DefaultTextPointer(int line, int lineOffset) {
- this.line = line;
- this.lineOffset = lineOffset;
- }
-
- @Override
- public int line() {
- return line;
- }
-
- @Override
- public int lineOffset() {
- return lineOffset;
- }
-
- @Override
- public String toString() {
- return "[line=" + line + ", lineOffset=" + lineOffset + "]";
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof DefaultTextPointer)) {
- return false;
- }
- DefaultTextPointer other = (DefaultTextPointer) obj;
- return other.line == this.line && other.lineOffset == this.lineOffset;
- }
-
- @Override
- public int hashCode() {
- return 37 * this.line + lineOffset;
- }
-
- @Override
- public int compareTo(TextPointer o) {
- if (this.line == o.line()) {
- return Integer.compare(this.lineOffset, o.lineOffset());
- }
- return Integer.compare(this.line, o.line());
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import org.sonar.api.batch.fs.TextPointer;
-import org.sonar.api.batch.fs.TextRange;
-
-/**
- * @since 5.2
- */
-public class DefaultTextRange implements TextRange {
-
- private final TextPointer start;
- private final TextPointer end;
-
- public DefaultTextRange(TextPointer start, TextPointer end) {
- this.start = start;
- this.end = end;
- }
-
- @Override
- public TextPointer start() {
- return start;
- }
-
- @Override
- public TextPointer end() {
- return end;
- }
-
- @Override
- public boolean overlap(TextRange another) {
- // [A,B] and [C,D]
- // B > C && D > A
- return this.end.compareTo(another.start()) > 0 && another.end().compareTo(this.start) > 0;
- }
-
- @Override
- public String toString() {
- return "Range[from " + start + " to " + end + "]";
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof DefaultTextRange)) {
- return false;
- }
- DefaultTextRange other = (DefaultTextRange) obj;
- return start.equals(other.start) && end.equals(other.end);
- }
-
- @Override
- public int hashCode() {
- return start.hashCode() * 17 + end.hashCode();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.Metadata;
-import org.sonar.scanner.fs.charhandler.CharHandler;
-import org.sonar.scanner.fs.charhandler.FileHashComputer;
-import org.sonar.scanner.fs.charhandler.LineCounter;
-import org.sonar.scanner.fs.charhandler.LineHashComputer;
-import org.sonar.scanner.fs.charhandler.LineOffsetCounter;
-
-/**
- * Computes hash of files. Ends of Lines are ignored, so files with
- * same content but different EOL encoding have the same hash.
- */
-@Immutable
-public class FileMetadata {
- private static final char LINE_FEED = '\n';
- private static final char CARRIAGE_RETURN = '\r';
-
- /**
- * Compute hash of a file ignoring line ends differences.
- * Maximum performance is needed.
- */
- public Metadata readMetadata(InputStream stream, Charset encoding, String filePath, @Nullable CharHandler otherHandler) {
- LineCounter lineCounter = new LineCounter(filePath, encoding);
- FileHashComputer fileHashComputer = new FileHashComputer(filePath);
- LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
-
- if (otherHandler != null) {
- CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter, otherHandler};
- readFile(stream, encoding, filePath, handlers);
- } else {
- CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
- readFile(stream, encoding, filePath, handlers);
- }
- return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(),
- lineOffsetCounter.getOriginalLineEndOffsets(),
- lineOffsetCounter.getLastValidOffset());
- }
-
- public Metadata readMetadata(InputStream stream, Charset encoding, String filePath) {
- return readMetadata(stream, encoding, filePath, null);
- }
-
- /**
- * For testing purpose
- */
- public Metadata readMetadata(Reader reader) {
- LineCounter lineCounter = new LineCounter("fromString", StandardCharsets.UTF_16);
- FileHashComputer fileHashComputer = new FileHashComputer("fromString");
- LineOffsetCounter lineOffsetCounter = new LineOffsetCounter();
- CharHandler[] handlers = {lineCounter, fileHashComputer, lineOffsetCounter};
-
- try {
- read(reader, handlers);
- } catch (IOException e) {
- throw new IllegalStateException("Should never occur", e);
- }
- return new Metadata(lineCounter.lines(), lineCounter.nonBlankLines(), fileHashComputer.getHash(), lineOffsetCounter.getOriginalLineStartOffsets(),
- lineOffsetCounter.getOriginalLineEndOffsets(),
- lineOffsetCounter.getLastValidOffset());
- }
-
- public static void readFile(InputStream stream, Charset encoding, String filePath, CharHandler[] handlers) {
- try (Reader reader = new BufferedReader(new InputStreamReader(stream, encoding))) {
- read(reader, handlers);
- } catch (IOException e) {
- throw new IllegalStateException(String.format("Fail to read file '%s' with encoding '%s'", filePath, encoding), e);
- }
- }
-
- private static void read(Reader reader, CharHandler[] handlers) throws IOException {
- char c;
- int i = reader.read();
- boolean afterCR = false;
- while (i != -1) {
- c = (char) i;
- if (afterCR) {
- for (CharHandler handler : handlers) {
- if (c == CARRIAGE_RETURN) {
- handler.newLine();
- handler.handleAll(c);
- } else if (c == LINE_FEED) {
- handler.handleAll(c);
- handler.newLine();
- } else {
- handler.newLine();
- handler.handleIgnoreEoL(c);
- handler.handleAll(c);
- }
- }
- afterCR = c == CARRIAGE_RETURN;
- } else if (c == LINE_FEED) {
- for (CharHandler handler : handlers) {
- handler.handleAll(c);
- handler.newLine();
- }
- } else if (c == CARRIAGE_RETURN) {
- afterCR = true;
- for (CharHandler handler : handlers) {
- handler.handleAll(c);
- }
- } else {
- for (CharHandler handler : handlers) {
- handler.handleIgnoreEoL(c);
- handler.handleAll(c);
- }
- }
- i = reader.read();
- }
- for (CharHandler handler : handlers) {
- if (afterCR) {
- handler.newLine();
- }
- handler.eof();
- }
- }
-
- @FunctionalInterface
- public interface LineHashConsumer {
- void consume(int lineIdx, @Nullable byte[] hash);
- }
-
- /**
- * Compute a MD5 hash of each line of the file after removing of all blank chars
- */
- public static void computeLineHashesForIssueTracking(InputFile f, LineHashConsumer consumer) {
- try {
- readFile(f.inputStream(), f.charset(), f.absolutePath(), new CharHandler[] {new LineHashComputer(consumer, f.file())});
- } catch (IOException e) {
- throw new IllegalStateException("Failed to compute line hashes for " + f.absolutePath(), e);
- }
- }
-}
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
+import org.sonar.api.impl.fs.DefaultInputModule;
@Immutable
public interface InputModuleHierarchy {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.Metadata;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.api.utils.PathUtils;
-
-/**
- * Intended to be used in unit tests that need to create {@link InputFile}s.
- * An InputFile is unambiguously identified by a <b>module key</b> and a <b>relative path</b>, so these parameters are mandatory.
- * <p>
- * A module base directory is only needed to construct absolute paths.
- * <p>
- * Examples of usage of the constructors:
- *
- * <pre>
- * InputFile file1 = TestInputFileBuilder.create("module1", "myfile.java").build();
- * InputFile file2 = TestInputFileBuilder.create("", fs.baseDir(), myfile).build();
- * </pre>
- * <p>
- * file1 will have the "module1" as both module key and module base directory.
- * file2 has an empty string as module key, and a relative path which is the path from the filesystem base directory to myfile.
- *
- * @since 6.3
- */
-public class TestInputFileBuilder {
- private static int batchId = 1;
-
- private final int id;
- private final String relativePath;
- private final String projectKey;
- @CheckForNull
- private Path projectBaseDir;
- private Path moduleBaseDir;
- private String language;
- private InputFile.Type type = InputFile.Type.MAIN;
- private InputFile.Status status;
- private int lines = -1;
- private Charset charset;
- private String hash;
- private int nonBlankLines;
- private int[] originalLineStartOffsets = new int[0];
- private int[] originalLineEndOffsets = new int[0];
- private int lastValidOffset = -1;
- private boolean publish = true;
- private String contents;
-
- /**
- * Create a InputFile identified by the given project key and relative path.
- */
- public TestInputFileBuilder(String projectKey, String relativePath) {
- this(projectKey, relativePath, batchId++);
- }
-
- /**
- * Create a InputFile with a given module key and module base directory.
- * The relative path is generated comparing the file path to the module base directory.
- * filePath must point to a file that is within the module base directory.
- */
- public TestInputFileBuilder(String projectKey, File moduleBaseDir, File filePath) {
- String relativePath = moduleBaseDir.toPath().relativize(filePath.toPath()).toString();
- this.projectKey = projectKey;
- setModuleBaseDir(moduleBaseDir.toPath());
- this.relativePath = PathUtils.sanitize(relativePath);
- this.id = batchId++;
- }
-
- public TestInputFileBuilder(String projectKey, String relativePath, int id) {
- this.projectKey = projectKey;
- setModuleBaseDir(Paths.get(projectKey));
- this.relativePath = PathUtils.sanitize(relativePath);
- this.id = id;
- }
-
- public static TestInputFileBuilder create(String moduleKey, File moduleBaseDir, File filePath) {
- return new TestInputFileBuilder(moduleKey, moduleBaseDir, filePath);
- }
-
- public static TestInputFileBuilder create(String moduleKey, String relativePath) {
- return new TestInputFileBuilder(moduleKey, relativePath);
- }
-
- public static int nextBatchId() {
- return batchId++;
- }
-
- public TestInputFileBuilder setProjectBaseDir(Path projectBaseDir) {
- this.projectBaseDir = normalize(projectBaseDir);
- return this;
- }
-
- public TestInputFileBuilder setModuleBaseDir(Path moduleBaseDir) {
- this.moduleBaseDir = normalize(moduleBaseDir);
- return this;
- }
-
- private static Path normalize(Path path) {
- try {
- return path.normalize().toRealPath(LinkOption.NOFOLLOW_LINKS);
- } catch (IOException e) {
- return path.normalize();
- }
- }
-
- public TestInputFileBuilder setLanguage(@Nullable String language) {
- this.language = language;
- return this;
- }
-
- public TestInputFileBuilder setType(InputFile.Type type) {
- this.type = type;
- return this;
- }
-
- public TestInputFileBuilder setStatus(InputFile.Status status) {
- this.status = status;
- return this;
- }
-
- public TestInputFileBuilder setLines(int lines) {
- this.lines = lines;
- return this;
- }
-
- public TestInputFileBuilder setCharset(Charset charset) {
- this.charset = charset;
- return this;
- }
-
- public TestInputFileBuilder setHash(String hash) {
- this.hash = hash;
- return this;
- }
-
- /**
- * Set contents of the file and calculates metadata from it.
- * The contents will be returned by {@link InputFile#contents()} and {@link InputFile#inputStream()} and can be
- * inconsistent with the actual physical file pointed by {@link InputFile#path()}, {@link InputFile#absolutePath()}, etc.
- */
- public TestInputFileBuilder setContents(String content) {
- this.contents = content;
- initMetadata(content);
- return this;
- }
-
- public TestInputFileBuilder setNonBlankLines(int nonBlankLines) {
- this.nonBlankLines = nonBlankLines;
- return this;
- }
-
- public TestInputFileBuilder setLastValidOffset(int lastValidOffset) {
- this.lastValidOffset = lastValidOffset;
- return this;
- }
-
- public TestInputFileBuilder setOriginalLineStartOffsets(int[] originalLineStartOffsets) {
- this.originalLineStartOffsets = originalLineStartOffsets;
- return this;
- }
-
- public TestInputFileBuilder setOriginalLineEndOffsets(int[] originalLineEndOffsets) {
- this.originalLineEndOffsets = originalLineEndOffsets;
- return this;
- }
-
- public TestInputFileBuilder setPublish(boolean publish) {
- this.publish = publish;
- return this;
- }
-
- public TestInputFileBuilder setMetadata(Metadata metadata) {
- this.setLines(metadata.lines());
- this.setLastValidOffset(metadata.lastValidOffset());
- this.setNonBlankLines(metadata.nonBlankLines());
- this.setHash(metadata.hash());
- this.setOriginalLineStartOffsets(metadata.originalLineStartOffsets());
- this.setOriginalLineEndOffsets(metadata.originalLineEndOffsets());
- return this;
- }
-
- public TestInputFileBuilder initMetadata(String content) {
- return setMetadata(new FileMetadata().readMetadata(new StringReader(content)));
- }
-
- public DefaultInputFile build() {
- Path absolutePath = moduleBaseDir.resolve(relativePath);
- if (projectBaseDir == null) {
- projectBaseDir = moduleBaseDir;
- }
- String projectRelativePath = projectBaseDir.relativize(absolutePath).toString();
- DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, projectKey, projectRelativePath, relativePath, type, language, id, new SensorStrategy());
- DefaultInputFile inputFile = new DefaultInputFile(indexedFile,
- f -> f.setMetadata(new Metadata(lines, nonBlankLines, hash, originalLineStartOffsets, originalLineEndOffsets, lastValidOffset)),
- contents);
- inputFile.setStatus(status);
- inputFile.setCharset(charset);
- inputFile.setPublished(publish);
- return inputFile;
- }
-
- public static DefaultInputModule newDefaultInputModule(String moduleKey, File baseDir) {
- ProjectDefinition definition = ProjectDefinition.create()
- .setKey(moduleKey)
- .setBaseDir(baseDir)
- .setWorkDir(new File(baseDir, ".sonar"));
- return newDefaultInputModule(definition);
- }
-
- public static DefaultInputModule newDefaultInputModule(ProjectDefinition projectDefinition) {
- return new DefaultInputModule(projectDefinition, TestInputFileBuilder.nextBatchId());
- }
-
- public static DefaultInputModule newDefaultInputModule(AbstractProjectOrModule parent, String key) throws IOException {
- Path basedir = parent.getBaseDir().resolve(key);
- Files.createDirectory(basedir);
- return newDefaultInputModule(key, basedir.toFile());
- }
-
- public static DefaultInputProject newDefaultInputProject(String projectKey, File baseDir) {
- ProjectDefinition definition = ProjectDefinition.create()
- .setKey(projectKey)
- .setBaseDir(baseDir)
- .setWorkDir(new File(baseDir, ".sonar"));
- return newDefaultInputProject(definition);
- }
-
- public static DefaultInputProject newDefaultInputProject(ProjectDefinition projectDefinition) {
- return new DefaultInputProject(projectDefinition, TestInputFileBuilder.nextBatchId());
- }
-
- public static DefaultInputProject newDefaultInputProject(String key, Path baseDir) throws IOException {
- Files.createDirectory(baseDir);
- return newDefaultInputProject(key, baseDir.toFile());
- }
-
- public static DefaultInputDir newDefaultInputDir(AbstractProjectOrModule module, String relativePath) throws IOException {
- Path basedir = module.getBaseDir().resolve(relativePath);
- Files.createDirectory(basedir);
- return new DefaultInputDir(module.key(), relativePath)
- .setModuleBaseDir(module.getBaseDir());
- }
-
- public static DefaultInputFile newDefaultInputFile(Path projectBaseDir, AbstractProjectOrModule module, String relativePath) {
- return new TestInputFileBuilder(module.key(), relativePath)
- .setStatus(InputFile.Status.SAME)
- .setProjectBaseDir(projectBaseDir)
- .setModuleBaseDir(module.getBaseDir())
- .build();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-public abstract class CharHandler {
-
- public void handleAll(char c) {
- }
-
- public void handleIgnoreEoL(char c) {
- }
-
- public void newLine() {
- }
-
- public void eof() {
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.codec.digest.DigestUtils;
-
-public class FileHashComputer extends CharHandler {
- private static final char LINE_FEED = '\n';
-
-
- private MessageDigest globalMd5Digest = DigestUtils.getMd5Digest();
- private StringBuilder sb = new StringBuilder();
- private final CharsetEncoder encoder;
- private final String filePath;
-
- public FileHashComputer(String filePath) {
- encoder = StandardCharsets.UTF_8.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- this.filePath = filePath;
- }
-
- @Override
- public void handleIgnoreEoL(char c) {
- sb.append(c);
- }
-
- @Override
- public void newLine() {
- sb.append(LINE_FEED);
- processBuffer();
- sb.setLength(0);
- }
-
- @Override
- public void eof() {
- if (sb.length() > 0) {
- processBuffer();
- }
- }
-
- private void processBuffer() {
- try {
- if (sb.length() > 0) {
- ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
- globalMd5Digest.update(encoded.array(), 0, encoded.limit());
- }
- } catch (CharacterCodingException e) {
- throw new IllegalStateException("Error encoding line hash in file: " + filePath, e);
- }
- }
-
- public String getHash() {
- return Hex.encodeHexString(globalMd5Digest.digest());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Specialization of {@link java.util.ArrayList} to create a list of int (only append elements) and then produce an int[].
- */
-class IntArrayList {
-
- /**
- * Default initial capacity.
- */
- private static final int DEFAULT_CAPACITY = 10;
-
- /**
- * Shared empty array instance used for default sized empty instances. We
- * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
- * first element is added.
- */
- private static final int[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
-
- /**
- * The array buffer into which the elements of the ArrayList are stored.
- * The capacity of the IntArrayList is the length of this array buffer. Any
- * empty IntArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
- * will be expanded to DEFAULT_CAPACITY when the first element is added.
- */
- private int[] elementData;
-
- /**
- * The size of the IntArrayList (the number of elements it contains).
- */
- private int size;
-
- /**
- * Constructs an empty list with an initial capacity of ten.
- */
- public IntArrayList() {
- this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
- }
-
- /**
- * Trims the capacity of this <tt>IntArrayList</tt> instance to be the
- * list's current size and return the internal array. An application can use this operation to minimize
- * the storage of an <tt>IntArrayList</tt> instance.
- */
- public int[] trimAndGet() {
- if (size < elementData.length) {
- elementData = Arrays.copyOf(elementData, size);
- }
- return elementData;
- }
-
- private void ensureCapacityInternal(int minCapacity) {
- int capacity = minCapacity;
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
- capacity = Math.max(DEFAULT_CAPACITY, minCapacity);
- }
-
- ensureExplicitCapacity(capacity);
- }
-
- private void ensureExplicitCapacity(int minCapacity) {
- if (minCapacity - elementData.length > 0) {
- grow(minCapacity);
- }
- }
-
- /**
- * Increases the capacity to ensure that it can hold at least the
- * number of elements specified by the minimum capacity argument.
- *
- * @param minCapacity the desired minimum capacity
- */
- private void grow(int minCapacity) {
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity < 0) {
- newCapacity = minCapacity;
- }
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
-
- /**
- * Appends the specified element to the end of this list.
- *
- * @param e element to be appended to this list
- * @return <tt>true</tt> (as specified by {@link Collection#add})
- */
- public boolean add(int e) {
- ensureCapacityInternal(size + 1);
- elementData[size] = e;
- size++;
- return true;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-import java.nio.charset.Charset;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-public class LineCounter extends CharHandler {
- private static final Logger LOG = Loggers.get(LineCounter.class);
-
- private int lines = 1;
- private int nonBlankLines = 0;
- private boolean blankLine = true;
- boolean alreadyLoggedInvalidCharacter = false;
- private final String filePath;
- private final Charset encoding;
-
- public LineCounter(String filePath, Charset encoding) {
- this.filePath = filePath;
- this.encoding = encoding;
- }
-
- @Override
- public void handleAll(char c) {
- if (!alreadyLoggedInvalidCharacter && c == '\ufffd') {
- LOG.warn("Invalid character encountered in file {} at line {} for encoding {}. Please fix file content or configure the encoding to be used using property '{}'.", filePath,
- lines, encoding, CoreProperties.ENCODING_PROPERTY);
- alreadyLoggedInvalidCharacter = true;
- }
- }
-
- @Override
- public void newLine() {
- lines++;
- if (!blankLine) {
- nonBlankLines++;
- }
- blankLine = true;
- }
-
- @Override
- public void handleIgnoreEoL(char c) {
- if (!Character.isWhitespace(c)) {
- blankLine = false;
- }
- }
-
- @Override
- public void eof() {
- if (!blankLine) {
- nonBlankLines++;
- }
- }
-
- public int lines() {
- return lines;
- }
-
- public int nonBlankLines() {
- return nonBlankLines;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-import java.io.File;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.sonar.scanner.fs.FileMetadata;
-
-public class LineHashComputer extends CharHandler {
- private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
- private final CharsetEncoder encoder;
- private final StringBuilder sb = new StringBuilder();
- private final FileMetadata.LineHashConsumer consumer;
- private final File file;
- private int line = 1;
-
- public LineHashComputer(FileMetadata.LineHashConsumer consumer, File f) {
- this.consumer = consumer;
- this.file = f;
- this.encoder = StandardCharsets.UTF_8.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
-
- @Override
- public void handleIgnoreEoL(char c) {
- if (!Character.isWhitespace(c)) {
- sb.append(c);
- }
- }
-
- @Override
- public void newLine() {
- processBuffer();
- sb.setLength(0);
- line++;
- }
-
- @Override
- public void eof() {
- if (this.line > 0) {
- processBuffer();
- }
- }
-
- private void processBuffer() {
- try {
- if (sb.length() > 0) {
- ByteBuffer encoded = encoder.encode(CharBuffer.wrap(sb));
- lineMd5Digest.update(encoded.array(), 0, encoded.limit());
- consumer.consume(line, lineMd5Digest.digest());
- }
- } catch (CharacterCodingException e) {
- throw new IllegalStateException("Error encoding line hash in file: " + file.getAbsolutePath(), e);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-public class LineOffsetCounter extends CharHandler {
- private long currentOriginalLineStartOffset = 0;
- private long currentOriginalLineEndOffset = 0;
- private final IntArrayList originalLineStartOffsets = new IntArrayList();
- private final IntArrayList originalLineEndOffsets = new IntArrayList();
- private long lastValidOffset = 0;
-
- public LineOffsetCounter() {
- originalLineStartOffsets.add(0);
- }
-
- @Override
- public void handleAll(char c) {
- currentOriginalLineStartOffset++;
- }
-
- @Override
- public void handleIgnoreEoL(char c) {
- currentOriginalLineEndOffset++;
- }
-
- @Override
- public void newLine() {
- if (currentOriginalLineStartOffset > Integer.MAX_VALUE) {
- throw new IllegalStateException("File is too big: " + currentOriginalLineStartOffset);
- }
- originalLineStartOffsets.add((int) currentOriginalLineStartOffset);
- originalLineEndOffsets.add((int) currentOriginalLineEndOffset);
- currentOriginalLineEndOffset = currentOriginalLineStartOffset;
- }
-
- @Override
- public void eof() {
- originalLineEndOffsets.add((int) currentOriginalLineEndOffset);
- lastValidOffset = currentOriginalLineStartOffset;
- }
-
- public int[] getOriginalLineStartOffsets() {
- return originalLineStartOffsets.trimAndGet();
- }
-
- public int[] getOriginalLineEndOffsets() {
- return originalLineEndOffsets.trimAndGet();
- }
-
- public int getLastValidOffset() {
- if (lastValidOffset > Integer.MAX_VALUE) {
- throw new IllegalStateException("File is too big: " + lastValidOffset);
- }
- return (int) lastValidOffset;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.scanner.fs.charhandler;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.PathUtils;
-
-/**
- * @since 4.2
- */
-class AbsolutePathPredicate extends AbstractFilePredicate {
-
- private final String path;
- private final Path baseDir;
-
- AbsolutePathPredicate(String path, Path baseDir) {
- this.baseDir = baseDir;
- this.path = PathUtils.sanitize(path);
- }
-
- @Override
- public boolean apply(InputFile f) {
- return path.equals(f.absolutePath());
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- String relative = PathUtils.sanitize(new PathResolver().relativePath(baseDir.toFile(), new File(path)));
- if (relative == null) {
- return Collections.emptyList();
- }
- InputFile f = index.inputFile(relative);
- return f != null ? Arrays.asList(f) : Collections.<InputFile>emptyList();
- }
-
- @Override
- public int priority() {
- return USE_INDEX;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.stream.StreamSupport;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * Partial implementation of {@link OptimizedFilePredicate}.
- * @since 5.1
- */
-public abstract class AbstractFilePredicate implements OptimizedFilePredicate {
-
- protected static final int DEFAULT_PRIORITY = 10;
- protected static final int USE_INDEX = 20;
-
- @Override
- public Iterable<InputFile> filter(Iterable<InputFile> target) {
- return () -> StreamSupport.stream(target.spliterator(), false)
- .filter(this::apply)
- .iterator();
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- return filter(index.inputFiles());
- }
-
- @Override
- public int priority() {
- return DEFAULT_PRIORITY;
- }
-
- @Override
- public final int compareTo(OptimizedFilePredicate o) {
- return o.priority() - priority();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-
-import static java.util.stream.Collectors.toList;
-
-/**
- * @since 4.2
- */
-class AndPredicate extends AbstractFilePredicate implements OperatorPredicate {
-
- private final List<OptimizedFilePredicate> predicates = new ArrayList<>();
-
- private AndPredicate() {
- }
-
- public static FilePredicate create(Collection<FilePredicate> predicates) {
- if (predicates.isEmpty()) {
- return TruePredicate.TRUE;
- }
- AndPredicate result = new AndPredicate();
- for (FilePredicate filePredicate : predicates) {
- if (filePredicate == TruePredicate.TRUE) {
- continue;
- } else if (filePredicate == FalsePredicate.FALSE) {
- return FalsePredicate.FALSE;
- } else if (filePredicate instanceof AndPredicate) {
- result.predicates.addAll(((AndPredicate) filePredicate).predicates);
- } else {
- result.predicates.add(OptimizedFilePredicateAdapter.create(filePredicate));
- }
- }
- Collections.sort(result.predicates);
- return result;
- }
-
- @Override
- public boolean apply(InputFile f) {
- for (OptimizedFilePredicate predicate : predicates) {
- if (!predicate.apply(f)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Iterable<InputFile> filter(Iterable<InputFile> target) {
- Iterable<InputFile> result = target;
- for (OptimizedFilePredicate predicate : predicates) {
- result = predicate.filter(result);
- }
- return result;
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- if (predicates.isEmpty()) {
- return index.inputFiles();
- }
- // Optimization, use get on first predicate then filter with next predicates
- Iterable<InputFile> result = predicates.get(0).get(index);
- for (int i = 1; i < predicates.size(); i++) {
- result = predicates.get(i).filter(result);
- }
- return result;
- }
-
- Collection<OptimizedFilePredicate> predicates() {
- return predicates;
- }
-
- @Override
- public List<FilePredicate> operands() {
- return predicates.stream().map(p -> (FilePredicate) p).collect(toList());
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.io.File;
-import java.net.URI;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FilePredicates;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.api.batch.fs.internal.PathPattern;
-
-/**
- * Factory of {@link FilePredicate}
- *
- * @since 4.2
- */
-public class DefaultFilePredicates implements FilePredicates {
-
- private final Path baseDir;
-
- /**
- * Client code should use {@link org.sonar.api.batch.fs.FileSystem#predicates()} to get an instance
- */
- public DefaultFilePredicates(Path baseDir) {
- this.baseDir = baseDir;
- }
-
- /**
- * Returns a predicate that always evaluates to true
- */
- @Override
- public FilePredicate all() {
- return TruePredicate.TRUE;
- }
-
- /**
- * Returns a predicate that always evaluates to false
- */
- @Override
- public FilePredicate none() {
- return FalsePredicate.FALSE;
- }
-
- @Override
- public FilePredicate hasAbsolutePath(String s) {
- return new AbsolutePathPredicate(s, baseDir);
- }
-
- /**
- * non-normalized path and Windows-style path are supported
- */
- @Override
- public FilePredicate hasRelativePath(String s) {
- return new RelativePathPredicate(s);
- }
-
- @Override
- public FilePredicate hasFilename(String s) {
- return new FilenamePredicate(s);
- }
-
- @Override
- public FilePredicate hasExtension(String s) {
- return new FileExtensionPredicate(s);
- }
-
- @Override
- public FilePredicate hasURI(URI uri) {
- return new URIPredicate(uri, baseDir);
- }
-
- @Override
- public FilePredicate matchesPathPattern(String inclusionPattern) {
- return new PathPatternPredicate(PathPattern.create(inclusionPattern));
- }
-
- @Override
- public FilePredicate matchesPathPatterns(String[] inclusionPatterns) {
- if (inclusionPatterns.length == 0) {
- return TruePredicate.TRUE;
- }
- FilePredicate[] predicates = new FilePredicate[inclusionPatterns.length];
- for (int i = 0; i < inclusionPatterns.length; i++) {
- predicates[i] = new PathPatternPredicate(PathPattern.create(inclusionPatterns[i]));
- }
- return or(predicates);
- }
-
- @Override
- public FilePredicate doesNotMatchPathPattern(String exclusionPattern) {
- return not(matchesPathPattern(exclusionPattern));
- }
-
- @Override
- public FilePredicate doesNotMatchPathPatterns(String[] exclusionPatterns) {
- if (exclusionPatterns.length == 0) {
- return TruePredicate.TRUE;
- }
- return not(matchesPathPatterns(exclusionPatterns));
- }
-
- @Override
- public FilePredicate hasPath(String s) {
- File file = new File(s);
- if (file.isAbsolute()) {
- return hasAbsolutePath(s);
- }
- return hasRelativePath(s);
- }
-
- @Override
- public FilePredicate is(File ioFile) {
- if (ioFile.isAbsolute()) {
- return hasAbsolutePath(ioFile.getAbsolutePath());
- }
- return hasRelativePath(ioFile.getPath());
- }
-
- @Override
- public FilePredicate hasLanguage(String language) {
- return new LanguagePredicate(language);
- }
-
- @Override
- public FilePredicate hasLanguages(Collection<String> languages) {
- List<FilePredicate> list = new ArrayList<>();
- for (String language : languages) {
- list.add(hasLanguage(language));
- }
- return or(list);
- }
-
- @Override
- public FilePredicate hasLanguages(String... languages) {
- List<FilePredicate> list = new ArrayList<>();
- for (String language : languages) {
- list.add(hasLanguage(language));
- }
- return or(list);
- }
-
- @Override
- public FilePredicate hasType(InputFile.Type type) {
- return new TypePredicate(type);
- }
-
- @Override
- public FilePredicate not(FilePredicate p) {
- return new NotPredicate(p);
- }
-
- @Override
- public FilePredicate or(Collection<FilePredicate> or) {
- return OrPredicate.create(or);
- }
-
- @Override
- public FilePredicate or(FilePredicate... or) {
- return OrPredicate.create(Arrays.asList(or));
- }
-
- @Override
- public FilePredicate or(FilePredicate first, FilePredicate second) {
- return OrPredicate.create(Arrays.asList(first, second));
- }
-
- @Override
- public FilePredicate and(Collection<FilePredicate> and) {
- return AndPredicate.create(and);
- }
-
- @Override
- public FilePredicate and(FilePredicate... and) {
- return AndPredicate.create(Arrays.asList(and));
- }
-
- @Override
- public FilePredicate and(FilePredicate first, FilePredicate second) {
- return AndPredicate.create(Arrays.asList(first, second));
- }
-
- @Override
- public FilePredicate hasStatus(Status status) {
- return new StatusPredicate(status);
- }
-
- @Override
- public FilePredicate hasAnyStatus() {
- return new StatusPredicate(null);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.Collections;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-
-class FalsePredicate extends AbstractFilePredicate {
-
- static final FilePredicate FALSE = new FalsePredicate();
-
- @Override
- public boolean apply(InputFile inputFile) {
- return false;
- }
-
- @Override
- public Iterable<InputFile> filter(Iterable<InputFile> target) {
- return Collections.emptyList();
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- return Collections.emptyList();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.Locale;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * @since 6.3
- */
-public class FileExtensionPredicate extends AbstractFilePredicate {
-
- private final String extension;
-
- public FileExtensionPredicate(String extension) {
- this.extension = lowercase(extension);
- }
-
- @Override
- public boolean apply(InputFile inputFile) {
- return extension.equals(getExtension(inputFile));
- }
-
- @Override
- public Iterable<InputFile> get(FileSystem.Index index) {
- return index.getFilesByExtension(extension);
- }
-
- public static String getExtension(InputFile inputFile) {
- return getExtension(inputFile.filename());
- }
-
- static String getExtension(String name) {
- int index = name.lastIndexOf('.');
- if (index < 0) {
- return "";
- }
- return lowercase(name.substring(index + 1));
- }
-
- private static String lowercase(String extension) {
- return extension.toLowerCase(Locale.ENGLISH);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * @since 6.3
- */
-public class FilenamePredicate extends AbstractFilePredicate {
- private final String filename;
-
- public FilenamePredicate(String filename) {
- this.filename = filename;
- }
-
- @Override
- public boolean apply(InputFile inputFile) {
- return filename.equals(inputFile.filename());
- }
-
- @Override
- public Iterable<InputFile> get(FileSystem.Index index) {
- return index.getFilesByName(filename);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * @since 4.2
- */
-class LanguagePredicate extends AbstractFilePredicate {
- private final String language;
-
- LanguagePredicate(String language) {
- this.language = language;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return language.equals(f.language());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.Arrays;
-import java.util.List;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.predicates.AbstractFilePredicate;
-import org.sonar.scanner.fs.predicates.OperatorPredicate;
-
-/**
- * @since 4.2
- */
-class NotPredicate extends AbstractFilePredicate implements OperatorPredicate {
-
- private final FilePredicate predicate;
-
- NotPredicate(FilePredicate predicate) {
- this.predicate = predicate;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return !predicate.apply(f);
- }
-
- @Override
- public List<FilePredicate> operands() {
- return Arrays.asList(predicate);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.List;
-import org.sonar.api.batch.fs.FilePredicate;
-
-/**
- * A predicate that associate other predicates
- */
-public interface OperatorPredicate extends FilePredicate {
-
- List<FilePredicate> operands();
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * Optimized version of FilePredicate allowing to speed up query by looking at InputFile by index.
- */
-public interface OptimizedFilePredicate extends FilePredicate, Comparable<OptimizedFilePredicate> {
-
- /**
- * Filter provided files to keep only the ones that are valid for this predicate
- */
- Iterable<InputFile> filter(Iterable<InputFile> inputFiles);
-
- /**
- * Get all files that are valid for this predicate.
- */
- Iterable<InputFile> get(FileSystem.Index index);
-
- /**
- * For optimization. FilePredicates will be applied in priority order. For example when doing
- * p.and(p1, p2, p3) then p1, p2 and p3 will be applied according to their priority value. Higher priority value
- * are applied first.
- * Assign a high priority when the predicate will likely highly reduce the set of InputFiles to filter. Also
- * {@link RelativePathPredicate} and AbsolutePathPredicate have a high priority since they are using cache index.
- */
- int priority();
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.InputFile;
-
-public class OptimizedFilePredicateAdapter extends AbstractFilePredicate {
-
- private FilePredicate unoptimizedPredicate;
-
- private OptimizedFilePredicateAdapter(FilePredicate unoptimizedPredicate) {
- this.unoptimizedPredicate = unoptimizedPredicate;
- }
-
- @Override
- public boolean apply(InputFile inputFile) {
- return unoptimizedPredicate.apply(inputFile);
- }
-
- public static OptimizedFilePredicate create(FilePredicate predicate) {
- if (predicate instanceof OptimizedFilePredicate) {
- return (OptimizedFilePredicate) predicate;
- } else {
- return new OptimizedFilePredicateAdapter(predicate);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * @since 4.2
- */
-class OrPredicate extends AbstractFilePredicate implements OperatorPredicate {
-
- private final List<FilePredicate> predicates = new ArrayList<>();
-
- private OrPredicate() {
- }
-
- public static FilePredicate create(Collection<FilePredicate> predicates) {
- if (predicates.isEmpty()) {
- return TruePredicate.TRUE;
- }
- OrPredicate result = new OrPredicate();
- for (FilePredicate filePredicate : predicates) {
- if (filePredicate == TruePredicate.TRUE) {
- return TruePredicate.TRUE;
- } else if (filePredicate == FalsePredicate.FALSE) {
- continue;
- } else if (filePredicate instanceof OrPredicate) {
- result.predicates.addAll(((OrPredicate) filePredicate).predicates);
- } else {
- result.predicates.add(filePredicate);
- }
- }
- return result;
- }
-
- @Override
- public boolean apply(InputFile f) {
- for (FilePredicate predicate : predicates) {
- if (predicate.apply(f)) {
- return true;
- }
- }
- return false;
- }
-
- Collection<FilePredicate> predicates() {
- return predicates;
- }
-
- @Override
- public List<FilePredicate> operands() {
- return predicates;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.nio.file.Paths;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.PathPattern;
-
-/**
- * @since 4.2
- */
-class PathPatternPredicate extends AbstractFilePredicate {
-
- private final PathPattern pattern;
-
- PathPatternPredicate(PathPattern pattern) {
- this.pattern = pattern;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return pattern.match(f.path(), Paths.get(f.relativePath()));
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.util.Collections;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.utils.PathUtils;
-
-/**
- * @since 4.2
- */
-public class RelativePathPredicate extends AbstractFilePredicate {
-
- @Nullable
- private final String path;
-
- RelativePathPredicate(String path) {
- this.path = PathUtils.sanitize(path);
- }
-
- public String path() {
- return path;
- }
-
- @Override
- public boolean apply(InputFile f) {
- if (path == null) {
- return false;
- }
-
- return path.equals(f.relativePath());
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- if (path != null) {
- InputFile f = index.inputFile(this.path);
- if (f != null) {
- return Collections.singletonList(f);
- }
- }
- return Collections.emptyList();
- }
-
- @Override
- public int priority() {
- return USE_INDEX;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.predicates.AbstractFilePredicate;
-
-/**
- * @deprecated since 7.8
- */
-@Deprecated
-public class StatusPredicate extends AbstractFilePredicate {
-
- private final InputFile.Status status;
-
- StatusPredicate(@Nullable InputFile.Status status) {
- this.status = status;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return status == null || status == f.status();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-
-class TruePredicate extends AbstractFilePredicate {
-
- static final FilePredicate TRUE = new TruePredicate();
-
- @Override
- public boolean apply(InputFile inputFile) {
- return true;
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- return index.inputFiles();
- }
-
- @Override
- public Iterable<InputFile> filter(Iterable<InputFile> target) {
- return target;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.sonar.api.batch.fs.InputFile;
-
-/**
- * @since 4.2
- */
-class TypePredicate extends AbstractFilePredicate {
-
- private final InputFile.Type type;
-
- TypePredicate(InputFile.Type type) {
- this.type = type;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return type == f.type();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.net.URI;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Optional;
-import org.sonar.api.batch.fs.FileSystem.Index;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.scan.filesystem.PathResolver;
-
-/**
- * @since 6.6
- */
-class URIPredicate extends AbstractFilePredicate {
-
- private final URI uri;
- private final Path baseDir;
-
- URIPredicate(URI uri, Path baseDir) {
- this.baseDir = baseDir;
- this.uri = uri;
- }
-
- @Override
- public boolean apply(InputFile f) {
- return uri.equals(f.uri());
- }
-
- @Override
- public Iterable<InputFile> get(Index index) {
- Path path = Paths.get(uri);
- Optional<String> relative = PathResolver.relativize(baseDir, path);
- if (!relative.isPresent()) {
- return Collections.emptyList();
- }
- InputFile f = index.inputFile(relative.get());
- return f != null ? Arrays.asList(f) : Collections.<InputFile>emptyList();
- }
-
- @Override
- public int priority() {
- return USE_INDEX;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.issue;
-
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.scanner.sensor.DefaultStorable;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.Issue.Flow;
-import org.sonar.api.batch.sensor.issue.IssueLocation;
-import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.utils.PathUtils;
-import org.sonar.scanner.fs.DefaultInputDir;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-
-import static java.util.Collections.unmodifiableList;
-import static java.util.stream.Collectors.toList;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable {
- protected IssueLocation primaryLocation;
- protected List<List<IssueLocation>> flows = new ArrayList<>();
- protected DefaultInputProject project;
-
- protected AbstractDefaultIssue(DefaultInputProject project) {
- this(project, null);
- }
-
- public AbstractDefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
- super(storage);
- this.project = project;
- }
-
- public IssueLocation primaryLocation() {
- return primaryLocation;
- }
-
- public List<Flow> flows() {
- return this.flows.stream()
- .<Flow>map(l -> () -> unmodifiableList(new ArrayList<>(l)))
- .collect(toList());
- }
-
- public NewIssueLocation newLocation() {
- return new DefaultIssueLocation();
- }
-
- public T at(NewIssueLocation primaryLocation) {
- checkArgument(primaryLocation != null, "Cannot use a location that is null");
- checkState(this.primaryLocation == null, "at() already called");
- this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation);
- checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component");
- return (T) this;
- }
-
- public T addLocation(NewIssueLocation secondaryLocation) {
- flows.add(Collections.singletonList(rewriteLocation((DefaultIssueLocation) secondaryLocation)));
- return (T) this;
- }
-
- public T addFlow(Iterable<NewIssueLocation> locations) {
- List<IssueLocation> flowAsList = new ArrayList<>();
- for (NewIssueLocation issueLocation : locations) {
- flowAsList.add(rewriteLocation((DefaultIssueLocation) issueLocation));
- }
- flows.add(flowAsList);
- return (T) this;
- }
-
- private DefaultIssueLocation rewriteLocation(DefaultIssueLocation location) {
- InputComponent component = location.inputComponent();
- Optional<Path> dirOrModulePath = Optional.empty();
-
- if (component instanceof DefaultInputDir) {
- DefaultInputDir dirComponent = (DefaultInputDir) component;
- dirOrModulePath = Optional.of(project.getBaseDir().relativize(dirComponent.path()));
- } else if (component instanceof DefaultInputModule && !Objects.equals(project.key(), component.key())) {
- DefaultInputModule moduleComponent = (DefaultInputModule) component;
- dirOrModulePath = Optional.of(project.getBaseDir().relativize(moduleComponent.getBaseDir()));
- }
-
- if (dirOrModulePath.isPresent()) {
- String path = PathUtils.sanitize(dirOrModulePath.get().toString());
- DefaultIssueLocation fixedLocation = new DefaultIssueLocation();
- fixedLocation.on(project);
- StringBuilder fullMessage = new StringBuilder();
- if (path != null && !path.isEmpty()) {
- fullMessage.append("[").append(path).append("] ");
- }
- fullMessage.append(location.message());
- fixedLocation.message(fullMessage.toString());
- return fixedLocation;
- } else {
- return location;
- }
- }
-}
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.DefaultTextRange;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultTextPointer;
+import org.sonar.api.impl.fs.DefaultTextRange;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
@ThreadSafe
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.issue;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.batch.sensor.issue.IssueLocation;
-import org.sonar.api.batch.sensor.issue.NewIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.scanner.fs.DefaultInputProject;
-
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue {
- private RuleKey ruleKey;
- private Double gap;
- private Severity overriddenSeverity;
-
- public DefaultIssue(DefaultInputProject project) {
- this(project, null);
- }
-
- public DefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
- super(project, storage);
- }
-
- public DefaultIssue forRule(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return this;
- }
-
- public RuleKey ruleKey() {
- return this.ruleKey;
- }
-
- @Override
- public DefaultIssue gap(@Nullable Double gap) {
- checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
- this.gap = gap;
- return this;
- }
-
- @Override
- public DefaultIssue overrideSeverity(@Nullable Severity severity) {
- this.overriddenSeverity = severity;
- return this;
- }
-
- @Override
- public Severity overriddenSeverity() {
- return this.overriddenSeverity;
- }
-
- @Override
- public Double gap() {
- return this.gap;
- }
-
- @Override
- public IssueLocation primaryLocation() {
- return primaryLocation;
- }
-
- @Override
- public void doSave() {
- requireNonNull(this.ruleKey, "ruleKey is mandatory on issue");
- checkState(primaryLocation != null, "Primary location is mandatory on every issue");
- storage.store(this);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.issue;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.issue.IssueLocation;
-import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-import static java.util.Objects.requireNonNull;
-import static org.apache.commons.lang.StringUtils.abbreviate;
-import static org.apache.commons.lang.StringUtils.trim;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
-
- private InputComponent component;
- private TextRange textRange;
- private String message;
-
- @Override
- public DefaultIssueLocation on(InputComponent component) {
- checkArgument(component != null, "Component can't be null");
- checkState(this.component == null, "on() already called");
- this.component = component;
- return this;
- }
-
- @Override
- public DefaultIssueLocation at(TextRange location) {
- checkState(this.component != null, "at() should be called after on()");
- checkState(this.component.isFile(), "at() should be called only for an InputFile.");
- DefaultInputFile file = (DefaultInputFile) this.component;
- file.validate(location);
- this.textRange = location;
- return this;
- }
-
- @Override
- public DefaultIssueLocation message(String message) {
- requireNonNull(message, "Message can't be null");
- if (message.contains("\u0000")) {
- throw new IllegalArgumentException(unsupportedCharacterError(message, component));
- }
- this.message = abbreviate(trim(message), MESSAGE_MAX_SIZE);
- return this;
- }
-
- private static String unsupportedCharacterError(String message, @Nullable InputComponent component) {
- String error = "Character \\u0000 is not supported in issue message '" + message + "'";
- if (component != null) {
- error += ", on component: " + component.toString();
- }
- return error;
- }
-
- @Override
- public InputComponent inputComponent() {
- return this.component;
- }
-
- @Override
- public TextRange textRange() {
- return textRange;
- }
-
- @Override
- public String message() {
- return this.message;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.issue;
-
-import java.util.Set;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.issue.NoSonarFilter;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-public class DefaultNoSonarFilter extends NoSonarFilter {
- public NoSonarFilter noSonarInFile(InputFile inputFile, Set<Integer> noSonarLines) {
- ((DefaultInputFile) inputFile).noSonarAt(noSonarLines);
- return this;
- }
-}
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.protocol.output.ScannerReport;
/**
import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.issue.Issue.Flow;
-import org.sonar.scanner.fs.DefaultInputComponent;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputComponent;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.Constants.Severity;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.IssueLocation;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.issue.DefaultFilterableIssue;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
import org.sonar.api.utils.WildcardPattern;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.issue.DefaultFilterableIssue;
public class IgnoreIssuesFilter implements IssueFilter {
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.charhandler.CharHandler;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.charhandler.CharHandler;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import java.util.stream.Collectors;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.charhandler.CharHandler;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.charhandler.CharHandler;
import org.sonar.scanner.issue.ignore.pattern.LineRange;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.scanner.fs.InputProject;
import org.sonar.core.util.CloseableIterator;
-import org.sonar.scanner.fs.DefaultInputComponent;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputComponent;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component;
import org.sonar.scanner.protocol.output.ScannerReport.Symbol;
import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.DateUtils;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import static org.apache.commons.lang.StringUtils.trimToEmpty;
public class DefaultServer extends Server {
private final Configuration settings;
- private final ScannerWsClient client;
+ private final DefaultScannerWsClient client;
private final SonarRuntime runtime;
- public DefaultServer(Configuration settings, ScannerWsClient client, SonarRuntime runtime) {
+ public DefaultServer(Configuration settings, DefaultScannerWsClient client, SonarRuntime runtime) {
this.settings = settings;
this.client = client;
this.runtime = runtime;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.postjob;
-
-import java.util.Arrays;
-import java.util.Collection;
-import org.sonar.api.batch.postjob.PostJobDescriptor;
-
-public class DefaultPostJobDescriptor implements PostJobDescriptor {
-
- private String name;
- private String[] properties = new String[0];
-
- public String name() {
- return name;
- }
-
- public Collection<String> properties() {
- return Arrays.asList(properties);
- }
-
- @Override
- public DefaultPostJobDescriptor name(String name) {
- this.name = name;
- return this;
- }
-
- @Override
- public DefaultPostJobDescriptor requireProperty(String... propertyKey) {
- return requireProperties(propertyKey);
- }
-
- @Override
- public DefaultPostJobDescriptor requireProperties(String... propertyKeys) {
- this.properties = propertyKeys;
- return this;
- }
-
-}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.config.Configuration;
+import org.sonar.api.impl.sensor.DefaultPostJobDescriptor;
public class PostJobOptimizer {
import org.sonar.api.batch.postjob.PostJob;
import org.sonar.api.batch.postjob.PostJobContext;
+import org.sonar.api.impl.sensor.DefaultPostJobDescriptor;
public class PostJobWrapper {
package org.sonar.scanner.report;
import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.scanner.rule.DefaultActiveRule;
+import org.sonar.api.batch.rule.DefaultActiveRule;
import org.sonar.scanner.protocol.Constants;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import java.util.TreeSet;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.api.utils.System2;
import org.sonar.core.platform.PluginInfo;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
+import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.ProjectServerSettings;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scm.ScmConfiguration;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.api.impl.utils.ScannerUtils;
public class ChangedLinesPublisher implements ReportPublisherStep {
private static final Logger LOG = Loggers.get(ChangedLinesPublisher.class);
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.scanner.fs.AbstractProjectOrModule;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus;
import org.sonar.scanner.bootstrap.ScannerPlugin;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.fs.AbstractProjectOrModule;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Metadata.BranchType;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
private static final String ID = "id";
private static final String RESOLVED = "resolved";
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
private final AnalysisContextReportPublisher contextPublisher;
private final InputModuleHierarchy moduleHierarchy;
private final GlobalAnalysisMode analysisMode;
private ScannerReportWriter writer;
private ScannerReportReader reader;
- public ReportPublisher(ScanProperties properties, ScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
+ public ReportPublisher(ScanProperties properties, DefaultScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher,
InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration) {
this.wsClient = wsClient;
this.server = server;
try {
response = wsClient.call(post).failIfNotSuccessful();
} catch (HttpException e) {
- throw MessageException.of(String.format("Failed to upload report - %s", ScannerWsClient.createErrorMessage(e)));
+ throw MessageException.of(String.format("Failed to upload report - %s", DefaultScannerWsClient.createErrorMessage(e)));
}
try (InputStream protobuf = response.contentStream()) {
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import java.util.stream.StreamSupport;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.impl.fs.DefaultInputComponent;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.sensor.DefaultMeasure;
import org.sonar.api.test.MutableTestPlan;
import org.sonar.api.test.TestCase;
import org.sonar.api.test.TestCase.Status;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
-import org.sonar.scanner.fs.DefaultInputComponent;
-import org.sonar.scanner.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
-import org.sonar.scanner.sensor.DefaultMeasure;
import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS;
import static org.sonar.api.measures.CoreMetrics.TESTS;
import java.util.List;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metric.ValueType;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.protocol.GsonHelper;
import org.sonarqube.ws.client.GetRequest;
public class DefaultMetricsRepositoryLoader implements MetricsRepositoryLoader {
private static final String METRICS_SEARCH_URL = "/api/metrics/search?f=name,description,direction,qualitative,custom&ps=500&p=";
- private ScannerWsClient wsClient;
+ private DefaultScannerWsClient wsClient;
- public DefaultMetricsRepositoryLoader(ScannerWsClient wsClient) {
+ public DefaultMetricsRepositoryLoader(DefaultScannerWsClient wsClient) {
this.wsClient = wsClient;
}
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.api.impl.utils.ScannerUtils;
import org.sonarqube.ws.Batch.WsProjectResponse;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;
public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoader {
private static final Logger LOG = LoggerFactory.getLogger(DefaultProjectRepositoriesLoader.class);
private static final String BATCH_PROJECT_URL = "/batch/project.protobuf";
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
- public DefaultProjectRepositoriesLoader(ScannerWsClient wsClient) {
+ public DefaultProjectRepositoriesLoader(DefaultScannerWsClient wsClient) {
this.wsClient = wsClient;
}
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.scan.ScanProperties;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
-import static org.sonar.scanner.util.ScannerUtils.encodeForUrl;
+import static org.sonar.api.impl.utils.ScannerUtils.encodeForUrl;
public class DefaultQualityProfileLoader implements QualityProfileLoader {
private static final String WS_URL = "/api/qualityprofiles/search.protobuf";
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
private final ScanProperties properties;
- public DefaultQualityProfileLoader(ScanProperties properties, ScannerWsClient wsClient) {
+ public DefaultQualityProfileLoader(ScanProperties properties, DefaultScannerWsClient wsClient) {
this.properties = properties;
this.wsClient = wsClient;
}
if (tryLoadDefault) {
return loadDefault();
} else {
- throw MessageException.of(errorMsg.get() + ": " + ScannerWsClient.createErrorMessage(e));
+ throw MessageException.of(errorMsg.get() + ": " + DefaultScannerWsClient.createErrorMessage(e));
}
}
- throw new IllegalStateException(errorMsg.get() + ": " + ScannerWsClient.createErrorMessage(e));
+ throw new IllegalStateException(errorMsg.get() + ": " + DefaultScannerWsClient.createErrorMessage(e));
} catch (MessageException e) {
throw e;
} catch (Exception e) {
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
@Immutable
public abstract class ProjectRepositories {
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.api.impl.utils.ScannerUtils;
import org.sonarqube.ws.Settings;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;
public abstract class AbstractSettingsLoader {
private static final Logger LOG = Loggers.get(AbstractSettingsLoader.class);
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
- public AbstractSettingsLoader(final ScannerWsClient wsClient) {
+ public AbstractSettingsLoader(final DefaultScannerWsClient wsClient) {
this.wsClient = wsClient;
}
package org.sonar.scanner.repository.settings;
import java.util.Map;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader {
- public DefaultGlobalSettingsLoader(final ScannerWsClient wsClient) {
+ public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) {
super(wsClient);
}
import java.util.Map;
import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
public class DefaultProjectSettingsLoader extends AbstractSettingsLoader implements ProjectSettingsLoader {
private final ProcessedScannerProperties scannerProperties;
- public DefaultProjectSettingsLoader(final ScannerWsClient wsClient, final ProcessedScannerProperties scannerProperties) {
+ public DefaultProjectSettingsLoader(final DefaultScannerWsClient wsClient, final ProcessedScannerProperties scannerProperties) {
super(wsClient);
this.scannerProperties = scannerProperties;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.rule.RuleKey;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Builds instances of {@link org.sonar.api.batch.rule.ActiveRules}.
- * <b>For unit testing and internal use only</b>.
- *
- * @since 4.2
- */
-public class ActiveRulesBuilder {
-
- private final Map<RuleKey, NewActiveRule> map = new LinkedHashMap<>();
-
- public ActiveRulesBuilder addRule(NewActiveRule newActiveRule) {
- if (map.containsKey(newActiveRule.ruleKey)) {
- throw new IllegalStateException(String.format("Rule '%s' is already activated", newActiveRule.ruleKey));
- }
- map.put(newActiveRule.ruleKey, newActiveRule);
- return this;
- }
-
- public ActiveRules build() {
- return new DefaultActiveRules(map.values());
- }
-}
package org.sonar.scanner.rule;
import java.util.List;
+import org.sonar.api.batch.rule.LoadedActiveRule;
public interface ActiveRulesLoader {
List<LoadedActiveRule> load(String qualityProfileKey);
import java.util.Set;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.batch.rule.NewActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.rule.ActiveRule;
-import org.sonar.api.rule.RuleKey;
-
-@Immutable
-public class DefaultActiveRule implements ActiveRule {
- private final RuleKey ruleKey;
- private final String severity;
- private final String internalKey;
- private final String language;
- private final String templateRuleKey;
- private final Map<String, String> params;
- private final long createdAt;
- private final long updatedAt;
- private final String qProfileKey;
-
- DefaultActiveRule(NewActiveRule newActiveRule) {
- this.severity = newActiveRule.severity;
- this.internalKey = newActiveRule.internalKey;
- this.templateRuleKey = newActiveRule.templateRuleKey;
- this.ruleKey = newActiveRule.ruleKey;
- this.params = Collections.unmodifiableMap(new HashMap<>(newActiveRule.params));
- this.language = newActiveRule.language;
- this.createdAt = newActiveRule.createdAt;
- this.updatedAt = newActiveRule.updatedAt;
- this.qProfileKey = newActiveRule.qProfileKey;
- }
-
- @Override
- public RuleKey ruleKey() {
- return ruleKey;
- }
-
- @Override
- public String severity() {
- return severity;
- }
-
- @Override
- public String language() {
- return language;
- }
-
- @Override
- public String param(String key) {
- return params.get(key);
- }
-
- @Override
- public Map<String, String> params() {
- // already immutable
- return params;
- }
-
- @Override
- public String internalKey() {
- return internalKey;
- }
-
- @Override
- public String templateRuleKey() {
- return templateRuleKey;
- }
-
- public long createdAt() {
- return createdAt;
- }
-
- public long updatedAt() {
- return updatedAt;
- }
-
- @Override
- public String qpKey() {
- return qProfileKey;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.rule.ActiveRule;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.rule.RuleKey;
-
-@Immutable
-public class DefaultActiveRules implements ActiveRules {
- private final Map<String, List<ActiveRule>> activeRulesByRepository = new HashMap<>();
- private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndKey = new HashMap<>();
- private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndInternalKey = new HashMap<>();
- private final Map<String, List<ActiveRule>> activeRulesByLanguage = new HashMap<>();
-
- public DefaultActiveRules(Collection<NewActiveRule> newActiveRules) {
- for (NewActiveRule newAR : newActiveRules) {
- DefaultActiveRule ar = new DefaultActiveRule(newAR);
- String repo = ar.ruleKey().repository();
- activeRulesByRepository.computeIfAbsent(repo, x -> new ArrayList<>()).add(ar);
- if (ar.language() != null) {
- activeRulesByLanguage.computeIfAbsent(ar.language(), x -> new ArrayList<>()).add(ar);
- }
-
- activeRulesByRepositoryAndKey.computeIfAbsent(repo, r -> new HashMap<>()).put(ar.ruleKey().rule(), ar);
- String internalKey = ar.internalKey();
- if (internalKey != null) {
- activeRulesByRepositoryAndInternalKey.computeIfAbsent(repo, r -> new HashMap<>()).put(internalKey, ar);
- }
- }
- }
-
- @Override
- public ActiveRule find(RuleKey ruleKey) {
- return activeRulesByRepositoryAndKey.getOrDefault(ruleKey.repository(), Collections.emptyMap())
- .get(ruleKey.rule());
- }
-
- @Override
- public Collection<ActiveRule> findAll() {
- return activeRulesByRepository.entrySet().stream().flatMap(x -> x.getValue().stream()).collect(Collectors.toList());
- }
-
- @Override
- public Collection<ActiveRule> findByRepository(String repository) {
- return activeRulesByRepository.getOrDefault(repository, Collections.emptyList());
- }
-
- @Override
- public Collection<ActiveRule> findByLanguage(String language) {
- return activeRulesByLanguage.getOrDefault(language, Collections.emptyList());
- }
-
- @Override
- public ActiveRule findByInternalKey(String repository, String internalKey) {
- return activeRulesByRepositoryAndInternalKey.containsKey(repository) ? activeRulesByRepositoryAndInternalKey.get(repository).get(internalKey) : null;
- }
-}
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
-import org.sonar.api.rule.RuleKey;
import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.api.impl.utils.ScannerUtils;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.DateUtils;
import org.sonarqube.ws.Rules;
import org.sonarqube.ws.Rules.Active;
import org.sonarqube.ws.Rules.Active.Param;
import org.sonarqube.ws.Rules.SearchResponse;
import org.sonarqube.ws.client.GetRequest;
-import static org.sonar.api.utils.DateUtils.dateToLong;
-import static org.sonar.api.utils.DateUtils.parseDateTime;
-
public class DefaultActiveRulesLoader implements ActiveRulesLoader {
private static final String RULES_SEARCH_URL = "/api/rules/search.protobuf?f=repo,name,severity,lang,internalKey,templateKey,params,actives,createdAt,updatedAt&activation=true";
loadedRule.setRuleKey(RuleKey.parse(r.getKey()));
loadedRule.setName(r.getName());
loadedRule.setSeverity(active.getSeverity());
- loadedRule.setCreatedAt(dateToLong(parseDateTime(active.getCreatedAt())));
- loadedRule.setUpdatedAt(dateToLong(parseDateTime(active.getUpdatedAt())));
+ loadedRule.setCreatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getCreatedAt())));
+ loadedRule.setUpdatedAt(DateUtils.dateToLong(DateUtils.parseDateTime(active.getUpdatedAt())));
loadedRule.setLanguage(r.getLang());
loadedRule.setInternalKey(r.getInternalKey());
if (r.hasTemplateKey()) {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.rule.Rule;
-import org.sonar.api.batch.rule.RuleParam;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-
-@Immutable
-public class DefaultRule implements Rule {
-
- private final RuleKey key;
- private final Integer id;
- private final String name;
- private final String severity;
- private final String type;
- private final String description;
- private final String internalKey;
- private final RuleStatus status;
- private final Map<String, RuleParam> params;
-
- DefaultRule(NewRule newRule) {
- this.key = newRule.key;
- this.id = newRule.id;
- this.name = newRule.name;
- this.severity = newRule.severity;
- this.type = newRule.type;
- this.description = newRule.description;
- this.internalKey = newRule.internalKey;
- this.status = newRule.status;
-
- Map<String, RuleParam> builder = new HashMap<>();
- for (NewRuleParam newRuleParam : newRule.params.values()) {
- builder.put(newRuleParam.key, new DefaultRuleParam(newRuleParam));
- }
- params = Collections.unmodifiableMap(builder);
- }
-
- @Override
- public RuleKey key() {
- return key;
- }
-
- @CheckForNull
- public Integer id() {
- return id;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- public String severity() {
- return severity;
- }
-
- @CheckForNull
- public String type() {
- return type;
- }
-
- @Override
- public String description() {
- return description;
- }
-
- @Override
- public String internalKey() {
- return internalKey;
- }
-
- @Override
- public RuleStatus status() {
- return status;
- }
-
- @Override
- public RuleParam param(String paramKey) {
- return params.get(paramKey);
- }
-
- @Override
- public Collection<RuleParam> params() {
- return params.values();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import org.sonar.api.batch.rule.RuleParam;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-@Immutable
-class DefaultRuleParam implements RuleParam {
-
- private final String key;
- private final String description;
-
- DefaultRuleParam(NewRuleParam p) {
- this.key = p.key;
- this.description = p.description;
- }
-
- @Override
- public String key() {
- return key;
- }
-
- @Override
- @Nullable
- public String description() {
- return description;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.annotation.concurrent.Immutable;
-import org.sonar.api.batch.rule.Rule;
-import org.sonar.api.batch.rule.Rules;
-import org.sonar.api.rule.RuleKey;
-
-@Immutable
-class DefaultRules implements Rules {
- private final Map<String, List<Rule>> rulesByRepository;
- private final Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKey;
- private final Map<RuleKey, Rule> rulesByRuleKey;
-
- DefaultRules(Collection<NewRule> newRules) {
- Map<String, List<Rule>> rulesByRepositoryBuilder = new HashMap<>();
- Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder = new HashMap<>();
- Map<RuleKey, Rule> rulesByRuleKeyBuilder = new HashMap<>();
-
- for (NewRule newRule : newRules) {
- DefaultRule r = new DefaultRule(newRule);
- rulesByRuleKeyBuilder.put(r.key(), r);
- rulesByRepositoryBuilder.computeIfAbsent(r.key().repository(), x -> new ArrayList<>()).add(r);
- addToTable(rulesByRepositoryAndInternalKeyBuilder, r);
- }
-
- rulesByRuleKey = Collections.unmodifiableMap(rulesByRuleKeyBuilder);
- rulesByRepository = Collections.unmodifiableMap(rulesByRepositoryBuilder);
- rulesByRepositoryAndInternalKey = Collections.unmodifiableMap(rulesByRepositoryAndInternalKeyBuilder);
- }
-
- private static void addToTable(Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder, DefaultRule r) {
- if (r.internalKey() == null) {
- return;
- }
-
- rulesByRepositoryAndInternalKeyBuilder
- .computeIfAbsent(r.key().repository(), x -> new HashMap<>())
- .computeIfAbsent(r.internalKey(), x -> new ArrayList<>())
- .add(r);
- }
-
- @Override
- public Rule find(RuleKey ruleKey) {
- return rulesByRuleKey.get(ruleKey);
- }
-
- @Override
- public Collection<Rule> findAll() {
- return rulesByRepository.values().stream().flatMap(List::stream).collect(Collectors.toList());
- }
-
- @Override
- public Collection<Rule> findByRepository(String repository) {
- return rulesByRepository.getOrDefault(repository, Collections.emptyList());
- }
-
- @Override
- public Collection<Rule> findByInternalKey(String repository, String internalKey) {
- return rulesByRepositoryAndInternalKey
- .getOrDefault(repository, Collections.emptyMap())
- .getOrDefault(internalKey, Collections.emptyList());
- }
-}
import java.io.InputStream;
import java.util.List;
import org.apache.commons.io.IOUtils;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonarqube.ws.Rules.ListResponse;
import org.sonarqube.ws.Rules.ListResponse.Rule;
import org.sonarqube.ws.client.GetRequest;
public class DefaultRulesLoader implements RulesLoader {
private static final String RULES_SEARCH_URL = "/api/rules/list.protobuf";
- private final ScannerWsClient wsClient;
+ private final DefaultScannerWsClient wsClient;
- public DefaultRulesLoader(ScannerWsClient wsClient) {
+ public DefaultRulesLoader(DefaultScannerWsClient wsClient) {
this.wsClient = wsClient;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.rule.RuleKey;
-
-public class LoadedActiveRule {
- private RuleKey ruleKey;
- private String severity;
- private String name;
- private String language;
- private Map<String, String> params;
- private long createdAt;
- private long updatedAt;
- private String templateRuleKey;
- private String internalKey;
-
- public RuleKey getRuleKey() {
- return ruleKey;
- }
-
- public void setRuleKey(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSeverity() {
- return severity;
- }
-
- public void setSeverity(String severity) {
- this.severity = severity;
- }
-
- public String getLanguage() {
- return language;
- }
-
- public void setLanguage(String language) {
- this.language = language;
- }
-
- public Map<String, String> getParams() {
- return params;
- }
-
- public void setParams(Map<String, String> params) {
- this.params = params;
- }
-
- public long getCreatedAt() {
- return createdAt;
- }
-
- public void setCreatedAt(long createdAt) {
- this.createdAt = createdAt;
- }
-
- public long getUpdatedAt() {
- return updatedAt;
- }
-
- public void setUpdatedAt(long updatedAt) {
- this.updatedAt = updatedAt;
- }
-
- @CheckForNull
- public String getTemplateRuleKey() {
- return templateRuleKey;
- }
-
- public void setTemplateRuleKey(@Nullable String templateRuleKey) {
- this.templateRuleKey = templateRuleKey;
- }
-
- public String getInternalKey() {
- return internalKey;
- }
-
- public void setInternalKey(String internalKey) {
- this.internalKey = internalKey;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-
-/**
- * @since 4.2
- */
-@Immutable
-public class NewActiveRule {
- final RuleKey ruleKey;
- final String name;
- final String severity;
- final Map<String, String> params;
- final long createdAt;
- final long updatedAt;
- final String internalKey;
- final String language;
- final String templateRuleKey;
- final String qProfileKey;
-
- NewActiveRule(Builder builder) {
- this.ruleKey = builder.ruleKey;
- this.name = builder.name;
- this.severity = builder.severity;
- this.params = builder.params;
- this.createdAt = builder.createdAt;
- this.updatedAt = builder.updatedAt;
- this.internalKey = builder.internalKey;
- this.language = builder.language;
- this.templateRuleKey = builder.templateRuleKey;
- this.qProfileKey = builder.qProfileKey;
- }
-
- public static class Builder {
- private RuleKey ruleKey;
- private String name;
- private String severity = Severity.defaultSeverity();
- private Map<String, String> params = new HashMap<>();
- private long createdAt;
- private long updatedAt;
- private String internalKey;
- private String language;
- private String templateRuleKey;
- private String qProfileKey;
-
- public Builder setRuleKey(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return this;
- }
-
- public Builder setName(String name) {
- this.name = name;
- return this;
- }
-
- public Builder setSeverity(@Nullable String severity) {
- this.severity = StringUtils.defaultIfBlank(severity, Severity.defaultSeverity());
- return this;
- }
-
- public Builder setParam(String key, @Nullable String value) {
- // possible improvement : check that the param key exists in rule definition
- if (value == null) {
- params.remove(key);
- } else {
- params.put(key, value);
- }
- return this;
- }
-
- public Builder setCreatedAt(long createdAt) {
- this.createdAt = createdAt;
- return this;
- }
-
- public Builder setUpdatedAt(long updatedAt) {
- this.updatedAt = updatedAt;
- return this;
- }
-
- public Builder setInternalKey(@Nullable String internalKey) {
- this.internalKey = internalKey;
- return this;
- }
-
- public Builder setLanguage(@Nullable String language) {
- this.language = language;
- return this;
- }
-
- public Builder setTemplateRuleKey(@Nullable String templateRuleKey) {
- this.templateRuleKey = templateRuleKey;
- return this;
- }
-
- public Builder setQProfileKey(String qProfileKey) {
- this.qProfileKey = qProfileKey;
- return this;
- }
-
- public NewActiveRule build() {
- return new NewActiveRule(this);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.ObjectUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-
-public class NewRule {
-
- private static final String DEFAULT_SEVERITY = Severity.defaultSeverity();
-
- final RuleKey key;
- Integer id;
- String name;
- String description;
- String severity = DEFAULT_SEVERITY;
- String type;
- String internalKey;
- RuleStatus status = RuleStatus.defaultStatus();
- Map<String, NewRuleParam> params = new HashMap<>();
-
- public NewRule(RuleKey key) {
- this.key = key;
- }
-
- public NewRule setId(@Nullable Integer id) {
- this.id = id;
- return this;
- }
-
- public NewRule setDescription(@Nullable String description) {
- this.description = description;
- return this;
- }
-
- public NewRule setName(@Nullable String s) {
- this.name = s;
- return this;
- }
-
- public NewRule setSeverity(@Nullable String severity) {
- this.severity = StringUtils.defaultIfBlank(severity, DEFAULT_SEVERITY);
- return this;
- }
-
- public NewRule setType(@Nullable String type) {
- this.type = type;
- return this;
- }
-
- public NewRule setStatus(@Nullable RuleStatus s) {
- this.status = (RuleStatus) ObjectUtils.defaultIfNull(s, RuleStatus.defaultStatus());
- return this;
- }
-
- public NewRule setInternalKey(@Nullable String s) {
- this.internalKey = s;
- return this;
- }
-
- public NewRuleParam addParam(String paramKey) {
- if (params.containsKey(paramKey)) {
- throw new IllegalStateException(String.format("Parameter '%s' already exists on rule '%s'", paramKey, key));
- }
- NewRuleParam param = new NewRuleParam(paramKey);
- params.put(paramKey, param);
- return param;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import javax.annotation.Nullable;
-
-public class NewRuleParam {
- final String key;
- String description;
-
- NewRuleParam(String key) {
- this.key = key;
- }
-
- public NewRuleParam setDescription(@Nullable String s) {
- description = s;
- return this;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import org.sonar.api.batch.rule.Rules;
-import org.sonar.api.rule.RuleKey;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * For unit testing and internal use only.
- *
- * @since 4.2
- */
-
-public class RulesBuilder {
-
- private final Map<RuleKey, NewRule> map = new HashMap<>();
-
- public NewRule add(RuleKey key) {
- if (map.containsKey(key)) {
- throw new IllegalStateException(String.format("Rule '%s' already exists", key));
- }
- NewRule newRule = new NewRule(key);
- map.put(key, newRule);
- return newRule;
- }
-
- public Rules build() {
- return new DefaultRules(map.values());
- }
-}
import java.util.List;
import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.rule.NewRule;
import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.impl.rule.RulesBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.scanner.fs.AbstractProjectOrModule;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
@Immutable
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
public class InputModuleHierarchyProvider extends ProviderAdapter {
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
public class InputProjectProvider extends ProviderAdapter {
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
public class ModuleConfigurationProvider extends ProviderAdapter {
package org.sonar.scanner.scan;
import org.picocontainer.Startable;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.ExtensionInstaller;
import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.sensor.ModuleSensorContext;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
public class ProjectConfigurationProvider extends ProviderAdapter {
import java.nio.file.Files;
import java.nio.file.Path;
import org.picocontainer.Startable;
-import org.sonar.scanner.fs.AbstractProjectOrModule;
+import org.sonar.api.impl.fs.AbstractProjectOrModule;
public class ProjectLock implements Startable {
private final DirectoryLock lock;
import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.api.impl.utils.ScannerUtils;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
-import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
+import static org.sonar.api.impl.config.MultivalueProperty.parseAsCsv;
/**
* Class that creates a project definition based on a set of properties.
import javax.annotation.Nullable;
import org.sonar.api.SonarEdition;
import org.sonar.api.SonarRuntime;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.FileMetadata;
+import org.sonar.api.impl.fs.SensorStrategy;
+import org.sonar.api.impl.issue.DefaultNoSonarFilter;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.deprecated.test.TestableBuilder;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.FileMetadata;
import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.issue.DefaultNoSonarFilter;
import org.sonar.scanner.issue.IssueFilters;
import org.sonar.scanner.issue.IssuePublisher;
import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
import java.util.Optional;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import static org.sonar.core.config.ScannerProperties.BRANCH_NAME;
import static org.sonar.core.config.ScannerProperties.ORGANIZATION;
import java.nio.file.Path;
import java.util.Iterator;
import org.sonar.core.util.FileUtils;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
/**
import org.sonar.api.utils.WildcardPattern;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import static java.util.stream.Collectors.toList;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.PathPattern;
+import org.sonar.api.impl.fs.PathPattern;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
package org.sonar.scanner.scan.filesystem;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.predicates.AbstractFilePredicate;
+import org.sonar.api.impl.fs.predicates.AbstractFilePredicate;
/**
* Additional {@link org.sonar.api.batch.fs.FilePredicate}s that are
package org.sonar.scanner.scan.filesystem;
import com.google.common.annotations.VisibleForTesting;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.predicates.DefaultFilePredicates;
public class DefaultModuleFileSystem extends DefaultFileSystem {
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) {
- super(module.getBaseDir(), moduleInputFileCache);
+ super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir()));
initFields(module);
}
package org.sonar.scanner.scan.filesystem;
import com.google.common.annotations.VisibleForTesting;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.predicates.DefaultFilePredicates;
public class DefaultProjectFileSystem extends DefaultFileSystem {
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) {
- super(project.getBaseDir(), inputComponentStore);
+ super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir()));
setFields(project);
}
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputFileFilter;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.impl.fs.SensorStrategy;
import org.sonar.api.batch.scm.IgnoreCommand;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultIndexedFile;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultIndexedFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.util.ProgressReport;
import javax.annotation.CheckForNull;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.predicates.FileExtensionPredicate;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.predicates.FileExtensionPredicate;
import org.sonar.scanner.scan.branch.BranchConfiguration;
/**
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.internal.PathPattern;
+import org.sonar.api.impl.fs.PathPattern;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.repository.language.Language;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.sonar.api.batch.fs.InputFile.Type;
-import org.sonar.api.batch.fs.internal.Metadata;
+import org.sonar.api.impl.fs.Metadata;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.FileMetadata;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.FileMetadata;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
public class MetadataGenerator {
package org.sonar.scanner.scan.filesystem;
import javax.annotation.concurrent.Immutable;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.scan.ModuleConfiguration;
@Immutable
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.SensorStrategy;
+import org.sonar.api.impl.fs.DefaultFileSystem;
@ScannerSide
public class ModuleInputComponentStore extends DefaultFileSystem.Cache {
package org.sonar.scanner.scan.filesystem;
import javax.annotation.concurrent.Immutable;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.scan.ProjectConfiguration;
@Immutable
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.ModuleConfiguration;
import org.sonar.scanner.scan.ModuleConfigurationProvider;
import javax.annotation.concurrent.Immutable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
import org.sonar.scanner.scm.ScmChangedFiles;
import org.sonar.api.batch.scm.BlameLine;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.scanner.util.ScannerUtils;
+import org.sonar.api.impl.utils.ScannerUtils;
public class ScmChangedFilesProvider extends ProviderAdapter {
private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class);
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Changesets.Builder;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.config.Configuration;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
public abstract class AbstractSensorOptimizer {
package org.sonar.scanner.sensor;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
import org.sonar.api.scanner.sensor.ProjectSensor;
public abstract class AbstractSensorWrapper<G extends ProjectSensor> {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.rule.AdHocRule;
-import org.sonar.api.batch.sensor.rule.NewAdHocRule;
-import org.sonar.api.rules.RuleType;
-
-import static org.apache.commons.lang.StringUtils.isNotBlank;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultAdHocRule extends DefaultStorable implements AdHocRule, NewAdHocRule {
- private Severity severity;
- private RuleType type;
- private String name;
- private String description;
- private String engineId;
- private String ruleId;
-
- public DefaultAdHocRule() {
- super(null);
- }
-
- public DefaultAdHocRule(@Nullable SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public DefaultAdHocRule severity(Severity severity) {
- this.severity = severity;
- return this;
- }
-
- @Override
- public String engineId() {
- return engineId;
- }
-
- @Override
- public String ruleId() {
- return ruleId;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @CheckForNull
- @Override
- public String description() {
- return description;
- }
-
- @Override
- public Severity severity() {
- return this.severity;
- }
-
- @Override
- public void doSave() {
- checkState(isNotBlank(engineId), "Engine id is mandatory on ad hoc rule");
- checkState(isNotBlank(ruleId), "Rule id is mandatory on ad hoc rule");
- checkState(isNotBlank(name), "Name is mandatory on every ad hoc rule");
- checkState(severity != null, "Severity is mandatory on every ad hoc rule");
- checkState(type != null, "Type is mandatory on every ad hoc rule");
- storage.store(this);
- }
-
- @Override
- public RuleType type() {
- return type;
- }
-
- @Override
- public DefaultAdHocRule engineId(String engineId) {
- this.engineId = engineId;
- return this;
- }
-
- @Override
- public DefaultAdHocRule ruleId(String ruleId) {
- this.ruleId = ruleId;
- return this;
- }
-
- @Override
- public DefaultAdHocRule name(String name) {
- this.name = name;
- return this;
- }
-
- @Override
- public DefaultAdHocRule description(@Nullable String description) {
- this.description = description;
- return this;
- }
-
- @Override
- public DefaultAdHocRule type(RuleType type) {
- this.type = type;
- return this;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextPointer;
-import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.api.batch.sensor.error.NewAnalysisError;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultAnalysisError extends DefaultStorable implements NewAnalysisError, AnalysisError {
- private InputFile inputFile;
- private String message;
- private TextPointer location;
-
- public DefaultAnalysisError() {
- super(null);
- }
-
- public DefaultAnalysisError(SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public InputFile inputFile() {
- return inputFile;
- }
-
- @Override
- public String message() {
- return message;
- }
-
- @Override
- public TextPointer location() {
- return location;
- }
-
- @Override
- public NewAnalysisError onFile(InputFile inputFile) {
- checkArgument(inputFile != null, "Cannot use a inputFile that is null");
- checkState(this.inputFile == null, "onFile() already called");
- this.inputFile = inputFile;
- return this;
- }
-
- @Override
- public NewAnalysisError message(String message) {
- this.message = message;
- return this;
- }
-
- @Override
- public NewAnalysisError at(TextPointer location) {
- checkState(this.location == null, "at() already called");
- this.location = location;
- return this;
- }
-
- @Override
- protected void doSave() {
- requireNonNull(this.inputFile, "inputFile is mandatory on AnalysisError");
- storage.store(this);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.sensor.coverage.CoverageType;
-import org.sonar.api.batch.sensor.coverage.NewCoverage;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultCoverage extends DefaultStorable implements NewCoverage {
-
- private InputFile inputFile;
- private CoverageType type;
- private int totalCoveredLines = 0;
- private int totalConditions = 0;
- private int totalCoveredConditions = 0;
- private SortedMap<Integer, Integer> hitsByLine = new TreeMap<>();
- private SortedMap<Integer, Integer> conditionsByLine = new TreeMap<>();
- private SortedMap<Integer, Integer> coveredConditionsByLine = new TreeMap<>();
-
- public DefaultCoverage() {
- super();
- }
-
- public DefaultCoverage(@Nullable SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public DefaultCoverage onFile(InputFile inputFile) {
- this.inputFile = inputFile;
- return this;
- }
-
- public InputFile inputFile() {
- return inputFile;
- }
-
- @Override
- public NewCoverage ofType(CoverageType type) {
- this.type = requireNonNull(type, "type can't be null");
- return this;
- }
-
- public CoverageType type() {
- return type;
- }
-
- @Override
- public NewCoverage lineHits(int line, int hits) {
- validateFile();
- if (isExcluded()) {
- return this;
- }
- validateLine(line);
-
- if (!hitsByLine.containsKey(line)) {
- hitsByLine.put(line, hits);
- if (hits > 0) {
- totalCoveredLines += 1;
- }
- }
- return this;
- }
-
- private void validateLine(int line) {
- checkState(line <= inputFile.lines(), "Line %s is out of range in the file %s (lines: %s)", line, inputFile, inputFile.lines());
- checkState(line > 0, "Line number must be strictly positive: %s", line);
- }
-
- private void validateFile() {
- requireNonNull(inputFile, "Call onFile() first");
- }
-
- @Override
- public NewCoverage conditions(int line, int conditions, int coveredConditions) {
- validateFile();
- if (isExcluded()) {
- return this;
- }
- validateLine(line);
-
- if (conditions > 0 && !conditionsByLine.containsKey(line)) {
- totalConditions += conditions;
- totalCoveredConditions += coveredConditions;
- conditionsByLine.put(line, conditions);
- coveredConditionsByLine.put(line, coveredConditions);
- }
- return this;
- }
-
- public int coveredLines() {
- return totalCoveredLines;
- }
-
- public int linesToCover() {
- return hitsByLine.size();
- }
-
- public int conditions() {
- return totalConditions;
- }
-
- public int coveredConditions() {
- return totalCoveredConditions;
- }
-
- public SortedMap<Integer, Integer> hitsByLine() {
- return Collections.unmodifiableSortedMap(hitsByLine);
- }
-
- public SortedMap<Integer, Integer> conditionsByLine() {
- return Collections.unmodifiableSortedMap(conditionsByLine);
- }
-
- public SortedMap<Integer, Integer> coveredConditionsByLine() {
- return Collections.unmodifiableSortedMap(coveredConditionsByLine);
- }
-
- @Override
- public void doSave() {
- validateFile();
- if (!isExcluded()) {
- storage.store(this);
- }
- }
-
- private boolean isExcluded() {
- return ((DefaultInputFile) inputFile).isExcludedForCoverage();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
-import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-import static java.util.Collections.unmodifiableList;
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
- private static final Logger LOG = Loggers.get(DefaultCpdTokens.class);
- private final List<TokensLine> result = new ArrayList<>();
- private DefaultInputFile inputFile;
- private int startLine = Integer.MIN_VALUE;
- private int startIndex = 0;
- private int currentIndex = 0;
- private StringBuilder sb = new StringBuilder();
- private TextRange lastRange;
- private boolean loggedTestCpdWarning = false;
-
- public DefaultCpdTokens(SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public DefaultCpdTokens onFile(InputFile inputFile) {
- this.inputFile = (DefaultInputFile) requireNonNull(inputFile, "file can't be null");
- return this;
- }
-
- public InputFile inputFile() {
- return inputFile;
- }
-
- @Override
- public NewCpdTokens addToken(int startLine, int startLineOffset, int endLine, int endLineOffset, String image) {
- checkInputFileNotNull();
- TextRange newRange;
- try {
- newRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to register token in file " + inputFile, e);
- }
- return addToken(newRange, image);
- }
-
- @Override
- public DefaultCpdTokens addToken(TextRange range, String image) {
- requireNonNull(range, "Range should not be null");
- requireNonNull(image, "Image should not be null");
- checkInputFileNotNull();
- if (isExcludedForDuplication()) {
- return this;
- }
- checkState(lastRange == null || lastRange.end().compareTo(range.start()) <= 0,
- "Tokens of file %s should be provided in order.\nPrevious token: %s\nLast token: %s", inputFile, lastRange, range);
-
- int line = range.start().line();
- if (line != startLine) {
- addNewTokensLine(result, startIndex, currentIndex, startLine, sb);
- startIndex = currentIndex + 1;
- startLine = line;
- }
- currentIndex++;
- sb.append(image);
- lastRange = range;
-
- return this;
- }
-
- private boolean isExcludedForDuplication() {
- if (inputFile.isExcludedForDuplication()) {
- return true;
- }
- if (inputFile.type() == InputFile.Type.TEST) {
- if (!loggedTestCpdWarning) {
- LOG.warn("Duplication reported for '{}' will be ignored because it's a test file.", inputFile);
- loggedTestCpdWarning = true;
- }
- return true;
- }
- return false;
- }
-
- public List<TokensLine> getTokenLines() {
- return unmodifiableList(new ArrayList<>(result));
- }
-
- private static void addNewTokensLine(List<TokensLine> result, int startUnit, int endUnit, int startLine, StringBuilder sb) {
- if (sb.length() != 0) {
- result.add(new TokensLine(startUnit, endUnit, startLine, sb.toString()));
- sb.setLength(0);
- }
- }
-
- @Override
- protected void doSave() {
- checkState(inputFile != null, "Call onFile() first");
- if (isExcludedForDuplication()) {
- return;
- }
- addNewTokensLine(result, startIndex, currentIndex, startLine, sb);
- storage.store(this);
- }
-
- private void checkInputFileNotNull() {
- checkState(inputFile != null, "Call onFile() first");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.ExternalIssue;
-import org.sonar.api.batch.sensor.issue.NewExternalIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.RuleType;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.issue.AbstractDefaultIssue;
-
-import static java.lang.String.format;
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIssue> implements ExternalIssue, NewExternalIssue {
- private Long effort;
- private Severity severity;
- private RuleType type;
- private String engineId;
- private String ruleId;
-
- public DefaultExternalIssue(DefaultInputProject project) {
- this(project, null);
- }
-
- public DefaultExternalIssue(DefaultInputProject project, @Nullable SensorStorage storage) {
- super(project, storage);
- }
-
- @Override
- public DefaultExternalIssue remediationEffortMinutes(@Nullable Long effort) {
- checkArgument(effort == null || effort >= 0, format("effort must be greater than or equal 0 (got %s)", effort));
- this.effort = effort;
- return this;
- }
-
- @Override
- public DefaultExternalIssue severity(Severity severity) {
- this.severity = severity;
- return this;
- }
-
- @Override
- public String engineId() {
- return engineId;
- }
-
- @Override
- public String ruleId() {
- return ruleId;
- }
-
- @Override
- public Severity severity() {
- return this.severity;
- }
-
- @Override
- public Long remediationEffort() {
- return this.effort;
- }
-
- @Override
- public void doSave() {
- requireNonNull(this.engineId, "Engine id is mandatory on external issue");
- requireNonNull(this.ruleId, "Rule id is mandatory on external issue");
- checkState(primaryLocation != null, "Primary location is mandatory on every external issue");
- checkState(primaryLocation.inputComponent().isFile(), "External issues must be located in files");
- checkState(primaryLocation.message() != null, "External issues must have a message");
- checkState(severity != null, "Severity is mandatory on every external issue");
- checkState(type != null, "Type is mandatory on every external issue");
- storage.store(this);
- }
-
- @Override
- public RuleType type() {
- return type;
- }
-
- @Override
- public NewExternalIssue engineId(String engineId) {
- this.engineId = engineId;
- return this;
- }
-
- @Override
- public NewExternalIssue ruleId(String ruleId) {
- this.ruleId = ruleId;
- return this;
- }
-
- @Override
- public DefaultExternalIssue forRule(RuleKey ruleKey) {
- this.engineId = ruleKey.repository();
- this.ruleId = ruleKey.rule();
- return this;
- }
-
- @Override
- public RuleKey ruleKey() {
- if (engineId != null && ruleId != null) {
- return RuleKey.of(RuleKey.EXTERNAL_RULE_REPO_PREFIX + engineId, ruleId);
- }
- return null;
- }
-
- @Override
- public DefaultExternalIssue type(RuleType type) {
- this.type = type;
- return this;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
-import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultHighlighting extends DefaultStorable implements NewHighlighting {
-
- private final List<SyntaxHighlightingRule> syntaxHighlightingRules;
- private DefaultInputFile inputFile;
-
- public DefaultHighlighting(SensorStorage storage) {
- super(storage);
- syntaxHighlightingRules = new ArrayList<>();
- }
-
- public List<SyntaxHighlightingRule> getSyntaxHighlightingRuleSet() {
- return syntaxHighlightingRules;
- }
-
- private void checkOverlappingBoundaries() {
- if (syntaxHighlightingRules.size() > 1) {
- Iterator<SyntaxHighlightingRule> it = syntaxHighlightingRules.iterator();
- SyntaxHighlightingRule previous = it.next();
- while (it.hasNext()) {
- SyntaxHighlightingRule current = it.next();
- if (previous.range().end().compareTo(current.range().start()) > 0 && (previous.range().end().compareTo(current.range().end()) < 0)) {
- String errorMsg = String.format("Cannot register highlighting rule for characters at %s as it " +
- "overlaps at least one existing rule", current.range());
- throw new IllegalStateException(errorMsg);
- }
- previous = current;
- }
- }
- }
-
- @Override
- public DefaultHighlighting onFile(InputFile inputFile) {
- requireNonNull(inputFile, "file can't be null");
- this.inputFile = (DefaultInputFile) inputFile;
- return this;
- }
-
- public InputFile inputFile() {
- return inputFile;
- }
-
- @Override
- public DefaultHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText) {
- checkInputFileNotNull();
- TextRange newRange;
- try {
- newRange = inputFile.newRange(startOffset, endOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to highlight file " + inputFile, e);
- }
- return highlight(newRange, typeOfText);
- }
-
- @Override
- public DefaultHighlighting highlight(int startLine, int startLineOffset, int endLine, int endLineOffset, TypeOfText typeOfText) {
- checkInputFileNotNull();
- TextRange newRange;
- try {
- newRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to highlight file " + inputFile, e);
- }
- return highlight(newRange, typeOfText);
- }
-
- @Override
- public DefaultHighlighting highlight(TextRange range, TypeOfText typeOfText) {
- SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(range, typeOfText);
- this.syntaxHighlightingRules.add(syntaxHighlightingRule);
- return this;
- }
-
- @Override
- protected void doSave() {
- checkInputFileNotNull();
- // Sort rules to avoid variation during consecutive runs
- Collections.sort(syntaxHighlightingRules, (left, right) -> {
- int result = left.range().start().compareTo(right.range().start());
- if (result == 0) {
- result = right.range().end().compareTo(left.range().end());
- }
- return result;
- });
- checkOverlappingBoundaries();
- storage.store(this);
- }
-
- private void checkInputFileNotNull() {
- checkState(inputFile != null, "Call onFile() first");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.Serializable;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.measure.Metric;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.measure.Measure;
-import org.sonar.api.batch.sensor.measure.NewMeasure;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G>, NewMeasure<G> {
-
- private InputComponent component;
- private Metric<G> metric;
- private G value;
- private boolean fromCore = false;
-
- public DefaultMeasure() {
- super();
- }
-
- public DefaultMeasure(@Nullable SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public DefaultMeasure<G> on(InputComponent component) {
- checkArgument(component != null, "Component can't be null");
- checkState(this.component == null, "on() already called");
- this.component = component;
- return this;
- }
-
- @Override
- public DefaultMeasure<G> forMetric(Metric<G> metric) {
- checkState(this.metric == null, "Metric already defined");
- requireNonNull(metric, "metric should be non null");
- this.metric = metric;
- return this;
- }
-
- @Override
- public DefaultMeasure<G> withValue(G value) {
- checkState(this.value == null, "Measure value already defined");
- requireNonNull(value, "Measure value can't be null");
- this.value = value;
- return this;
- }
-
- /**
- * For internal use.
- */
- public boolean isFromCore() {
- return fromCore;
- }
-
- /**
- * For internal use. Used by core components to bypass check that prevent a plugin to store core measures.
- */
- public DefaultMeasure<G> setFromCore() {
- this.fromCore = true;
- return this;
- }
-
- @Override
- public void doSave() {
- requireNonNull(this.value, "Measure value can't be null");
- requireNonNull(this.metric, "Measure metric can't be null");
- checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type %s", this.metric.valueType());
- storage.store(this);
- }
-
- @Override
- public Metric<G> metric() {
- return metric;
- }
-
- @Override
- public InputComponent inputComponent() {
- return component;
- }
-
- @Override
- public G value() {
- return value;
- }
-
- // 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;
- }
- DefaultMeasure<?> rhs = (DefaultMeasure<?>) obj;
- return new EqualsBuilder()
- .append(component, rhs.component)
- .append(metric, rhs.metric)
- .append(value, rhs.value)
- .isEquals();
- }
-
- @Override
- public int hashCode() {
- return new HashCodeBuilder(27, 45).append(component).append(metric).append(value).toHashCode();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.function.Predicate;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.config.Configuration;
-
-import static java.util.Arrays.asList;
-
-public class DefaultSensorDescriptor implements SensorDescriptor {
-
- private String name;
- private String[] languages = new String[0];
- private InputFile.Type type = null;
- private String[] ruleRepositories = new String[0];
- private boolean global = false;
- private Predicate<Configuration> configurationPredicate;
-
- public String name() {
- return name;
- }
-
- public Collection<String> languages() {
- return Arrays.asList(languages);
- }
-
- @Nullable
- public InputFile.Type type() {
- return type;
- }
-
- public Collection<String> ruleRepositories() {
- return Arrays.asList(ruleRepositories);
- }
-
- public Predicate<Configuration> configurationPredicate() {
- return configurationPredicate;
- }
-
- public boolean isGlobal() {
- return global;
- }
-
- @Override
- public DefaultSensorDescriptor name(String name) {
- this.name = name;
- return this;
- }
-
- @Override
- public DefaultSensorDescriptor onlyOnLanguage(String languageKey) {
- return onlyOnLanguages(languageKey);
- }
-
- @Override
- public DefaultSensorDescriptor onlyOnLanguages(String... languageKeys) {
- this.languages = languageKeys;
- return this;
- }
-
- @Override
- public DefaultSensorDescriptor onlyOnFileType(InputFile.Type type) {
- this.type = type;
- return this;
- }
-
- @Override
- public DefaultSensorDescriptor createIssuesForRuleRepository(String... repositoryKey) {
- return createIssuesForRuleRepositories(repositoryKey);
- }
-
- @Override
- public DefaultSensorDescriptor createIssuesForRuleRepositories(String... repositoryKeys) {
- this.ruleRepositories = repositoryKeys;
- return this;
- }
-
- @Override
- public DefaultSensorDescriptor requireProperty(String... propertyKey) {
- return requireProperties(propertyKey);
- }
-
- @Override
- public DefaultSensorDescriptor requireProperties(String... propertyKeys) {
- this.configurationPredicate = config -> asList(propertyKeys).stream().allMatch(config::hasKey);
- return this;
- }
-
- @Override
- public SensorDescriptor global() {
- this.global = true;
- return this;
- }
-
- @Override
- public SensorDescriptor onlyWhenConfiguration(Predicate<Configuration> configurationPredicate) {
- this.configurationPredicate = configurationPredicate;
- return this;
- }
-
-}
import org.sonar.api.batch.sensor.rule.AdHocRule;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.config.Configuration;
+import org.sonar.api.impl.fs.DefaultInputComponent;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.sensor.DefaultCoverage;
+import org.sonar.api.impl.sensor.DefaultCpdTokens;
+import org.sonar.api.impl.sensor.DefaultHighlighting;
+import org.sonar.api.impl.sensor.DefaultMeasure;
+import org.sonar.api.impl.sensor.DefaultSignificantCode;
+import org.sonar.api.impl.sensor.DefaultSymbolTable;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.log.Logger;
import org.sonar.duplications.block.Block;
import org.sonar.duplications.internal.pmd.PmdBlockChunker;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputComponent;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
import org.sonar.scanner.issue.IssuePublisher;
import org.sonar.scanner.protocol.Constants;
import org.sonar.scanner.protocol.output.FileStructure;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.SortedMap;
-import java.util.TreeMap;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.code.NewSignificantCode;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.utils.Preconditions;
-
-public class DefaultSignificantCode extends DefaultStorable implements NewSignificantCode {
- private SortedMap<Integer, TextRange> significantCodePerLine = new TreeMap<>();
- private InputFile inputFile;
-
- public DefaultSignificantCode() {
- super();
- }
-
- public DefaultSignificantCode(@Nullable SensorStorage storage) {
- super(storage);
- }
-
- @Override
- public DefaultSignificantCode onFile(InputFile inputFile) {
- this.inputFile = inputFile;
- return this;
- }
-
- @Override
- public DefaultSignificantCode addRange(TextRange range) {
- Preconditions.checkState(this.inputFile != null, "addRange() should be called after on()");
-
- int line = range.start().line();
-
- Preconditions.checkArgument(line == range.end().line(), "Ranges of significant code must be located in a single line");
- Preconditions.checkState(!significantCodePerLine.containsKey(line), "Significant code was already reported for line '%s'. Can only report once per line.", line);
-
- significantCodePerLine.put(line, range);
- return this;
- }
-
- @Override
- protected void doSave() {
- Preconditions.checkState(inputFile != null, "Call onFile() first");
- storage.store(this);
- }
-
- public InputFile inputFile() {
- return inputFile;
- }
-
- public SortedMap<Integer, TextRange> significantCodePerLine() {
- return significantCodePerLine;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import javax.annotation.Nullable;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public abstract class DefaultStorable {
-
- protected final transient SensorStorage storage;
- private transient boolean saved = false;
-
- public DefaultStorable() {
- this.storage = null;
- }
-
- public DefaultStorable(@Nullable SensorStorage storage) {
- this.storage = storage;
- }
-
- public final void save() {
- requireNonNull(this.storage, "No persister on this object");
- checkState(!saved, "This object was already saved");
- doSave();
- this.saved = true;
- }
-
- protected abstract void doSave();
-
- @Override
- public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.symbol.NewSymbol;
-import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
-import org.sonar.scanner.fs.DefaultInputFile;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.api.utils.Preconditions.checkArgument;
-import static org.sonar.api.utils.Preconditions.checkState;
-
-public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTable {
-
- private final Map<TextRange, Set<TextRange>> referencesBySymbol;
- private DefaultInputFile inputFile;
-
- public DefaultSymbolTable(SensorStorage storage) {
- super(storage);
- referencesBySymbol = new LinkedHashMap<>();
- }
-
- public Map<TextRange, Set<TextRange>> getReferencesBySymbol() {
- return referencesBySymbol;
- }
-
- @Override
- public DefaultSymbolTable onFile(InputFile inputFile) {
- requireNonNull(inputFile, "file can't be null");
- this.inputFile = (DefaultInputFile) inputFile;
- return this;
- }
-
- public InputFile inputFile() {
- return inputFile;
- }
-
- @Override
- public NewSymbol newSymbol(int startLine, int startLineOffset, int endLine, int endLineOffset) {
- checkInputFileNotNull();
- TextRange declarationRange;
- try {
- declarationRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to create symbol on file " + inputFile, e);
- }
- return newSymbol(declarationRange);
- }
-
- @Override
- public NewSymbol newSymbol(int startOffset, int endOffset) {
- checkInputFileNotNull();
- TextRange declarationRange;
- try {
- declarationRange = inputFile.newRange(startOffset, endOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to create symbol on file " + inputFile, e);
- }
- return newSymbol(declarationRange);
- }
-
- @Override
- public NewSymbol newSymbol(TextRange range) {
- checkInputFileNotNull();
- TreeSet<TextRange> references = new TreeSet<>((o1, o2) -> o1.start().compareTo(o2.start()));
- referencesBySymbol.put(range, references);
- return new DefaultSymbol(inputFile, range, references);
- }
-
- private static class DefaultSymbol implements NewSymbol {
-
- private final Collection<TextRange> references;
- private final DefaultInputFile inputFile;
- private final TextRange declaration;
-
- public DefaultSymbol(DefaultInputFile inputFile, TextRange declaration, Collection<TextRange> references) {
- this.inputFile = inputFile;
- this.declaration = declaration;
- this.references = references;
- }
-
- @Override
- public NewSymbol newReference(int startOffset, int endOffset) {
- TextRange referenceRange;
- try {
- referenceRange = inputFile.newRange(startOffset, endOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to create symbol reference on file " + inputFile, e);
- }
- return newReference(referenceRange);
- }
-
- @Override
- public NewSymbol newReference(int startLine, int startLineOffset, int endLine, int endLineOffset) {
- TextRange referenceRange;
- try {
- referenceRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset);
- } catch (Exception e) {
- throw new IllegalArgumentException("Unable to create symbol reference on file " + inputFile, e);
- }
- return newReference(referenceRange);
- }
-
- @Override
- public NewSymbol newReference(TextRange range) {
- requireNonNull(range, "Provided range is null");
- checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration);
- references.add(range);
- return this;
- }
-
- }
-
- @Override
- protected void doSave() {
- checkInputFileNotNull();
- storage.store(this);
- }
-
- private void checkInputFileNotNull() {
- checkState(inputFile != null, "Call onFile() first");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.sonar.api.batch.sensor.code.NewSignificantCode;
-import org.sonar.api.batch.sensor.coverage.NewCoverage;
-import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
-import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.issue.ExternalIssue;
-import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.batch.sensor.measure.Measure;
-import org.sonar.api.batch.sensor.rule.AdHocRule;
-import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
-
-import static org.sonar.api.utils.Preconditions.checkArgument;
-
-class InMemorySensorStorage implements SensorStorage {
-
- Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>();
-
- Collection<Issue> allIssues = new ArrayList<>();
- Collection<ExternalIssue> allExternalIssues = new ArrayList<>();
- Collection<AdHocRule> allAdHocRules = new ArrayList<>();
- Collection<AnalysisError> allAnalysisErrors = new ArrayList<>();
-
- Map<String, NewHighlighting> highlightingByComponent = new HashMap<>();
- Map<String, DefaultCpdTokens> cpdTokensByComponent = new HashMap<>();
- Map<String, List<DefaultCoverage>> coverageByComponent = new HashMap<>();
- Map<String, DefaultSymbolTable> symbolsPerComponent = new HashMap<>();
- Map<String, String> contextProperties = new HashMap<>();
- Map<String, DefaultSignificantCode> significantCodePerComponent = new HashMap<>();
-
- @Override
- public void store(Measure measure) {
- // Emulate duplicate measure check
- String componentKey = measure.inputComponent().key();
- String metricKey = measure.metric().key();
- if (measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).containsKey(metricKey)) {
- throw new IllegalStateException("Can not add the same measure twice");
- }
- measuresByComponentAndMetric.computeIfAbsent(componentKey, x -> new HashMap<>()).put(metricKey, measure);
- }
-
- @Override
- public void store(Issue issue) {
- allIssues.add(issue);
- }
-
- @Override
- public void store(AdHocRule adHocRule) {
- allAdHocRules.add(adHocRule);
- }
-
- @Override
- public void store(NewHighlighting newHighlighting) {
- DefaultHighlighting highlighting = (DefaultHighlighting) newHighlighting;
- String fileKey = highlighting.inputFile().key();
- // Emulate duplicate storage check
- if (highlightingByComponent.containsKey(fileKey)) {
- throw new UnsupportedOperationException("Trying to save highlighting twice for the same file is not supported: " + highlighting.inputFile());
- }
- highlightingByComponent.put(fileKey, highlighting);
- }
-
- @Override
- public void store(NewCoverage coverage) {
- DefaultCoverage defaultCoverage = (DefaultCoverage) coverage;
- String fileKey = defaultCoverage.inputFile().key();
- coverageByComponent.computeIfAbsent(fileKey, x -> new ArrayList<>()).add(defaultCoverage);
- }
-
- @Override
- public void store(NewCpdTokens cpdTokens) {
- DefaultCpdTokens defaultCpdTokens = (DefaultCpdTokens) cpdTokens;
- String fileKey = defaultCpdTokens.inputFile().key();
- // Emulate duplicate storage check
- if (cpdTokensByComponent.containsKey(fileKey)) {
- throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + defaultCpdTokens.inputFile());
- }
- cpdTokensByComponent.put(fileKey, defaultCpdTokens);
- }
-
- @Override
- public void store(NewSymbolTable newSymbolTable) {
- DefaultSymbolTable symbolTable = (DefaultSymbolTable) newSymbolTable;
- String fileKey = symbolTable.inputFile().key();
- // Emulate duplicate storage check
- if (symbolsPerComponent.containsKey(fileKey)) {
- throw new UnsupportedOperationException("Trying to save symbol table twice for the same file is not supported: " + symbolTable.inputFile());
- }
- symbolsPerComponent.put(fileKey, symbolTable);
- }
-
- @Override
- public void store(AnalysisError analysisError) {
- allAnalysisErrors.add(analysisError);
- }
-
- @Override
- public void storeProperty(String key, String value) {
- checkArgument(key != null, "Key of context property must not be null");
- checkArgument(value != null, "Value of context property must not be null");
- contextProperties.put(key, value);
- }
-
- @Override
- public void store(ExternalIssue issue) {
- allExternalIssues.add(issue);
- }
-
- @Override
- public void store(NewSignificantCode newSignificantCode) {
- DefaultSignificantCode significantCode = (DefaultSignificantCode) newSignificantCode;
- String fileKey = significantCode.inputFile().key();
- // Emulate duplicate storage check
- if (significantCodePerComponent.containsKey(fileKey)) {
- throw new UnsupportedOperationException("Trying to save significant code information twice for the same file is not supported: " + significantCode.inputFile());
- }
- significantCodePerComponent.put(fileKey, significantCode);
- }
-}
import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
@ThreadSafe
public class ModuleSensorContext extends ProjectSensorContext {
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.impl.fs.SensorStrategy;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.logs.Profiler;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
public class ModuleSensorsExecutor {
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.config.Configuration;
import org.sonar.api.config.Settings;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.issue.DefaultIssue;
+import org.sonar.api.impl.sensor.DefaultAdHocRule;
+import org.sonar.api.impl.sensor.DefaultCoverage;
+import org.sonar.api.impl.sensor.DefaultCpdTokens;
+import org.sonar.api.impl.sensor.DefaultExternalIssue;
+import org.sonar.api.impl.sensor.DefaultHighlighting;
+import org.sonar.api.impl.sensor.DefaultMeasure;
+import org.sonar.api.impl.sensor.DefaultSignificantCode;
+import org.sonar.api.impl.sensor.DefaultSymbolTable;
import org.sonar.api.scanner.fs.InputProject;
import org.sonar.api.utils.Version;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.issue.DefaultIssue;
import org.sonar.scanner.sensor.noop.NoOpNewAnalysisError;
@ThreadSafe
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.File;
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Stream;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputModule;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.code.NewSignificantCode;
-import org.sonar.api.batch.sensor.coverage.NewCoverage;
-import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
-import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
-import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.api.batch.sensor.error.NewAnalysisError;
-import org.sonar.api.batch.sensor.highlighting.NewHighlighting;
-import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-import org.sonar.api.batch.sensor.issue.ExternalIssue;
-import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.batch.sensor.issue.NewExternalIssue;
-import org.sonar.api.batch.sensor.issue.NewIssue;
-import org.sonar.api.batch.sensor.measure.Measure;
-import org.sonar.api.batch.sensor.measure.NewMeasure;
-import org.sonar.api.batch.sensor.rule.AdHocRule;
-import org.sonar.api.batch.sensor.rule.NewAdHocRule;
-import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.scanner.fs.InputProject;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.Version;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.issue.DefaultIssue;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
-
-import static java.util.Collections.unmodifiableMap;
-
-/**
- * Utility class to help testing {@link Sensor}. This is not an API and method signature may evolve.
- * <p>
- * Usage: call {@link #create(File)} to create an "in memory" implementation of {@link SensorContext} with a filesystem initialized with provided baseDir.
- * <p>
- * You have to manually register inputFiles using:
- * <pre>
- * sensorContextTester.fileSystem().add(new DefaultInputFile("myProjectKey", "src/Foo.java")
- * .setLanguage("java")
- * .initMetadata("public class Foo {\n}"));
- * </pre>
- * <p>
- * Then pass it to your {@link Sensor}. You can then query elements provided by your sensor using methods {@link #allIssues()}, ...
- */
-public class SensorContextTester implements SensorContext {
-
- private Settings settings;
- private DefaultFileSystem fs;
- private ActiveRules activeRules;
- private InMemorySensorStorage sensorStorage;
- private DefaultInputProject project;
- private DefaultInputModule module;
- private SonarRuntime runtime;
- private boolean cancelled;
-
- private SensorContextTester(Path moduleBaseDir) {
- this.settings = new MapSettings();
- this.fs = new DefaultFileSystem(moduleBaseDir).setEncoding(Charset.defaultCharset());
- this.activeRules = new ActiveRulesBuilder().build();
- this.sensorStorage = new InMemorySensorStorage();
- this.project = new DefaultInputProject(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
- this.module = new DefaultInputModule(ProjectDefinition.create().setKey("projectKey").setBaseDir(moduleBaseDir.toFile()).setWorkDir(moduleBaseDir.resolve(".sonar").toFile()));
- this.runtime = SonarRuntimeImpl.forSonarQube(MetadataLoader.loadVersion(System2.INSTANCE), SonarQubeSide.SCANNER, MetadataLoader.loadEdition(System2.INSTANCE));
- }
-
- public static SensorContextTester create(File moduleBaseDir) {
- return new SensorContextTester(moduleBaseDir.toPath());
- }
-
- public static SensorContextTester create(Path moduleBaseDir) {
- return new SensorContextTester(moduleBaseDir);
- }
-
- @Override
- public Settings settings() {
- return settings;
- }
-
- @Override
- public Configuration config() {
- return new ConfigurationBridge(settings);
- }
-
- public SensorContextTester setSettings(Settings settings) {
- this.settings = settings;
- return this;
- }
-
- @Override
- public DefaultFileSystem fileSystem() {
- return fs;
- }
-
- public SensorContextTester setFileSystem(DefaultFileSystem fs) {
- this.fs = fs;
- return this;
- }
-
- @Override
- public ActiveRules activeRules() {
- return activeRules;
- }
-
- public SensorContextTester setActiveRules(ActiveRules activeRules) {
- this.activeRules = activeRules;
- return this;
- }
-
- /**
- * Default value is the version of this API at compilation time. You can override it
- * using {@link #setRuntime(SonarRuntime)} to test your Sensor behaviour.
- */
- @Override
- public Version getSonarQubeVersion() {
- return runtime().getApiVersion();
- }
-
- /**
- * @see #setRuntime(SonarRuntime) to override defaults (SonarQube scanner with version
- * of this API as used at compilation time).
- */
- @Override
- public SonarRuntime runtime() {
- return runtime;
- }
-
- public SensorContextTester setRuntime(SonarRuntime runtime) {
- this.runtime = runtime;
- return this;
- }
-
- @Override
- public boolean isCancelled() {
- return cancelled;
- }
-
- public void setCancelled(boolean cancelled) {
- this.cancelled = cancelled;
- }
-
- @Override
- public InputModule module() {
- return module;
- }
-
- @Override
- public InputProject project() {
- return project;
- }
-
- @Override
- public <G extends Serializable> NewMeasure<G> newMeasure() {
- return new DefaultMeasure<>(sensorStorage);
- }
-
- public Collection<Measure> measures(String componentKey) {
- return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).values();
- }
-
- public <G extends Serializable> Measure<G> measure(String componentKey, Metric<G> metric) {
- return measure(componentKey, metric.key());
- }
-
- public <G extends Serializable> Measure<G> measure(String componentKey, String metricKey) {
- return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).get(metricKey);
- }
-
- @Override
- public NewIssue newIssue() {
- return new DefaultIssue(project, sensorStorage);
- }
-
- public Collection<Issue> allIssues() {
- return sensorStorage.allIssues;
- }
-
- @Override
- public NewExternalIssue newExternalIssue() {
- return new DefaultExternalIssue(project, sensorStorage);
- }
-
- @Override
- public NewAdHocRule newAdHocRule() {
- return new DefaultAdHocRule(sensorStorage);
- }
-
- public Collection<ExternalIssue> allExternalIssues() {
- return sensorStorage.allExternalIssues;
- }
-
- public Collection<AdHocRule> allAdHocRules() {
- return sensorStorage.allAdHocRules;
- }
-
- public Collection<AnalysisError> allAnalysisErrors() {
- return sensorStorage.allAnalysisErrors;
- }
-
- @CheckForNull
- public Integer lineHits(String fileKey, int line) {
- return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
- .map(c -> c.hitsByLine().get(line))
- .flatMap(Stream::of)
- .filter(Objects::nonNull)
- .reduce(null, SensorContextTester::sumOrNull);
- }
-
- @CheckForNull
- public static Integer sumOrNull(@Nullable Integer o1, @Nullable Integer o2) {
- return o1 == null ? o2 : (o1 + o2);
- }
-
- @CheckForNull
- public Integer conditions(String fileKey, int line) {
- return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
- .map(c -> c.conditionsByLine().get(line))
- .flatMap(Stream::of)
- .filter(Objects::nonNull)
- .reduce(null, SensorContextTester::maxOrNull);
- }
-
- @CheckForNull
- public Integer coveredConditions(String fileKey, int line) {
- return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
- .map(c -> c.coveredConditionsByLine().get(line))
- .flatMap(Stream::of)
- .filter(Objects::nonNull)
- .reduce(null, SensorContextTester::maxOrNull);
- }
-
- @CheckForNull
- public TextRange significantCodeTextRange(String fileKey, int line) {
- if (sensorStorage.significantCodePerComponent.containsKey(fileKey)) {
- return sensorStorage.significantCodePerComponent.get(fileKey)
- .significantCodePerLine()
- .get(line);
- }
- return null;
-
- }
-
- @CheckForNull
- public static Integer maxOrNull(@Nullable Integer o1, @Nullable Integer o2) {
- return o1 == null ? o2 : Math.max(o1, o2);
- }
-
- @CheckForNull
- public List<TokensLine> cpdTokens(String componentKey) {
- DefaultCpdTokens defaultCpdTokens = sensorStorage.cpdTokensByComponent.get(componentKey);
- return defaultCpdTokens != null ? defaultCpdTokens.getTokenLines() : null;
- }
-
- @Override
- public NewHighlighting newHighlighting() {
- return new DefaultHighlighting(sensorStorage);
- }
-
- @Override
- public NewCoverage newCoverage() {
- return new DefaultCoverage(sensorStorage);
- }
-
- @Override
- public NewCpdTokens newCpdTokens() {
- return new DefaultCpdTokens(sensorStorage);
- }
-
- @Override
- public NewSymbolTable newSymbolTable() {
- return new DefaultSymbolTable(sensorStorage);
- }
-
- @Override
- public NewAnalysisError newAnalysisError() {
- return new DefaultAnalysisError(sensorStorage);
- }
-
- /**
- * Return list of syntax highlighting applied for a given position in a file. The result is a list because in theory you
- * can apply several styles to the same range.
- *
- * @param componentKey Key of the file like 'myProjectKey:src/foo.php'
- * @param line Line you want to query
- * @param lineOffset Offset you want to query.
- * @return List of styles applied to this position or empty list if there is no highlighting at this position.
- */
- public List<TypeOfText> highlightingTypeAt(String componentKey, int line, int lineOffset) {
- DefaultHighlighting syntaxHighlightingData = (DefaultHighlighting) sensorStorage.highlightingByComponent.get(componentKey);
- if (syntaxHighlightingData == null) {
- return Collections.emptyList();
- }
- List<TypeOfText> result = new ArrayList<>();
- DefaultTextPointer location = new DefaultTextPointer(line, lineOffset);
- for (SyntaxHighlightingRule sortedRule : syntaxHighlightingData.getSyntaxHighlightingRuleSet()) {
- if (sortedRule.range().start().compareTo(location) <= 0 && sortedRule.range().end().compareTo(location) > 0) {
- result.add(sortedRule.getTextType());
- }
- }
- return result;
- }
-
- /**
- * Return list of symbol references ranges for the symbol at a given position in a file.
- *
- * @param componentKey Key of the file like 'myProjectKey:src/foo.php'
- * @param line Line you want to query
- * @param lineOffset Offset you want to query.
- * @return List of references for the symbol (potentially empty) or null if there is no symbol at this position.
- */
- @CheckForNull
- public Collection<TextRange> referencesForSymbolAt(String componentKey, int line, int lineOffset) {
- DefaultSymbolTable symbolTable = sensorStorage.symbolsPerComponent.get(componentKey);
- if (symbolTable == null) {
- return null;
- }
- DefaultTextPointer location = new DefaultTextPointer(line, lineOffset);
- for (Map.Entry<TextRange, Set<TextRange>> symbol : symbolTable.getReferencesBySymbol().entrySet()) {
- if (symbol.getKey().start().compareTo(location) <= 0 && symbol.getKey().end().compareTo(location) > 0) {
- return symbol.getValue();
- }
- }
- return null;
- }
-
- @Override
- public void addContextProperty(String key, String value) {
- sensorStorage.storeProperty(key, value);
- }
-
- /**
- * @return an immutable map of the context properties defined with {@link SensorContext#addContextProperty(String, String)}.
- * @since 6.1
- */
- public Map<String, String> getContextProperties() {
- return unmodifiableMap(sensorStorage.contextProperties);
- }
-
- @Override
- public void markForPublishing(InputFile inputFile) {
- DefaultInputFile file = (DefaultInputFile) inputFile;
- file.setPublished(true);
- }
-
- @Override
- public NewSignificantCode newSignificantCode() {
- return new DefaultSignificantCode(sensorStorage);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-
-public class SyntaxHighlightingRule {
-
- private final TextRange range;
- private final TypeOfText textType;
-
- private SyntaxHighlightingRule(TextRange range, TypeOfText textType) {
- this.range = range;
- this.textType = textType;
- }
-
- public static SyntaxHighlightingRule create(TextRange range, TypeOfText textType) {
- return new SyntaxHighlightingRule(range, textType);
- }
-
- public TextRange range() {
- return range;
- }
-
- public TypeOfText getTextType() {
- return textType;
- }
-
- @Override
- public String toString() {
- return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
- }
-}
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.coverage.NewCoverage;
import org.sonar.api.scanner.sensor.ProjectSensor;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.report.ReportPublisher;
@Phase(name = Phase.Name.POST)
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.util;
-
-import com.google.common.base.Strings;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-
-public class ScannerUtils {
-
- private ScannerUtils() {
- }
-
- /**
- * Clean provided string to remove chars that are not valid as file name.
- * @param projectKey e.g. my:file
- */
- public static String cleanKeyForFilename(String projectKey) {
- String cleanKey = StringUtils.deleteWhitespace(projectKey);
- return StringUtils.replace(cleanKey, ":", "_");
- }
-
- public static String encodeForUrl(@Nullable String url) {
- try {
- return URLEncoder.encode(Strings.nullToEmpty(url), "UTF-8");
-
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException("Encoding not supported", e);
- }
- }
-
- public static String describe(Object o) {
- try {
- if (o.getClass().getMethod("toString").getDeclaringClass() != Object.class) {
- String str = o.toString();
- if (str != null) {
- return str;
- }
- }
- } catch (Exception e) {
- // fallback
- }
-
- return o.getClass().getName();
- }
-
- public static String pluralize(String str, int i) {
- if (i == 1) {
- return str;
- }
- return str + "s";
- }
-
-}
import org.mockito.ArgumentCaptor;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.internal.SensorStorage;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultMeasure;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.mockito.ArgumentMatcher;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonarqube.ws.client.WsRequest;
import org.sonarqube.ws.client.WsResponse;
import static org.mockito.Mockito.when;
public class WsTestUtil {
- public static void mockStream(ScannerWsClient mock, String path, InputStream is) {
+ public static void mockStream(DefaultScannerWsClient mock, String path, InputStream is) {
WsResponse response = mock(WsResponse.class);
when(response.contentStream()).thenReturn(is);
when(mock.call(argThat(new RequestMatcher(path)))).thenReturn(response);
}
- public static void mockStream(ScannerWsClient mock, InputStream is) {
+ public static void mockStream(DefaultScannerWsClient mock, InputStream is) {
WsResponse response = mock(WsResponse.class);
when(response.contentStream()).thenReturn(is);
when(mock.call(any(WsRequest.class))).thenReturn(response);
}
- public static void mockReader(ScannerWsClient mock, Reader reader) {
+ public static void mockReader(DefaultScannerWsClient mock, Reader reader) {
WsResponse response = mock(WsResponse.class);
when(response.contentReader()).thenReturn(reader);
when(mock.call(any(WsRequest.class))).thenReturn(response);
}
- public static void mockReader(ScannerWsClient mock, String path, Reader reader, Reader... others) {
+ public static void mockReader(DefaultScannerWsClient mock, String path, Reader reader, Reader... others) {
WsResponse response = mock(WsResponse.class);
when(response.contentReader()).thenReturn(reader);
WsResponse[] otherResponses = new WsResponse[others.length];
when(mock.call(argThat(new RequestMatcher(path)))).thenReturn(response, otherResponses);
}
- public static void mockException(ScannerWsClient mock, Exception e) {
+ public static void mockException(DefaultScannerWsClient mock, Exception e) {
when(mock.call(any(WsRequest.class))).thenThrow(e);
}
- public static void mockException(ScannerWsClient mock, String path, Exception e) {
+ public static void mockException(DefaultScannerWsClient mock, String path, Exception e) {
when(mock.call(argThat(new RequestMatcher(path)))).thenThrow(e);
}
- public static void verifyCall(ScannerWsClient mock, String path) {
+ public static void verifyCall(DefaultScannerWsClient mock, String path) {
verify(mock).call(argThat(new RequestMatcher(path)));
}
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.utils.TempFolder;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.scanner.bootstrap;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.MockWsResponse;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DefaultScannerWsClientTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ WsClient wsClient = mock(WsClient.class, Mockito.RETURNS_DEEP_STUBS);
+
+ @Test
+ public void log_and_profile_request_if_debug_level() {
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setRequestUrl("https://local/api/issues/search");
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+ DefaultScannerWsClient underTest = new DefaultScannerWsClient(wsClient, false, new GlobalAnalysisMode(
+ new RawScannerProperties(Collections.emptyMap())));
+
+ WsResponse result = underTest.call(request);
+
+ // do not fail the execution -> interceptor returns the response
+ assertThat(result).isSameAs(response);
+
+ // check logs
+ List<String> debugLogs = logTester.logs(LoggerLevel.DEBUG);
+ assertThat(debugLogs).hasSize(1);
+ assertThat(debugLogs.get(0)).contains("GET 200 https://local/api/issues/search | time=");
+ }
+
+ @Test
+ public void create_error_msg_from_json() {
+ String content = "{\"errors\":[{\"msg\":\"missing scan permission\"}, {\"msg\":\"missing another permission\"}]}";
+ assertThat(DefaultScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).isEqualTo("missing scan permission, missing another permission");
+ }
+
+ @Test
+ public void create_error_msg_from_html() {
+ String content = "<!DOCTYPE html><html>something</html>";
+ assertThat(DefaultScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).isEqualTo("HTTP code 400");
+ }
+
+ @Test
+ public void create_error_msg_from_long_content() {
+ String content = StringUtils.repeat("mystring", 1000);
+ assertThat(DefaultScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).hasSize(15 + 128);
+ }
+
+ @Test
+ public void fail_if_requires_credentials() {
+ expectedException.expect(MessageException.class);
+ expectedException
+ .expectMessage("Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties sonar.login and sonar.password.");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setCode(401);
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new DefaultScannerWsClient(wsClient, false, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
+ }
+
+ @Test
+ public void fail_if_credentials_are_not_valid() {
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password.");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setCode(401);
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new DefaultScannerWsClient(wsClient, /* credentials are configured */true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
+ }
+
+ @Test
+ public void fail_if_requires_permission() {
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("You're not authorized to run analysis. Please contact the project administrator.");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse()
+ .setCode(403);
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new DefaultScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
+ }
+
+ @Test
+ public void fail_if_bad_request() {
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("Boo! bad request! bad!");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse()
+ .setCode(400)
+ .setContent("{\"errors\":[{\"msg\":\"Boo! bad request! bad!\"}]}");
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new DefaultScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
+ }
+
+ private MockWsResponse newResponse() {
+ return new MockWsResponse().setRequestUrl("https://local/api/issues/search");
+ }
+
+ private WsRequest newRequest() {
+ return new GetRequest("api/issues/search");
+ }
+}
import org.sonar.api.Plugin;
import org.sonar.api.SonarRuntime;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginInfo;
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.impl.sensor.DefaultSensorDescriptor;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.sensor.DefaultSensorDescriptor;
import org.sonar.scanner.sensor.ModuleSensorContext;
import org.sonar.scanner.sensor.ModuleSensorExtensionDictionnary;
import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.scanner.bootstrap.ScannerPluginInstaller.InstalledPlugin;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.WsClientFactories;
public void setUp() throws Exception {
HttpConnector connector = HttpConnector.newBuilder().url(server.url("/").toString()).build();
GlobalAnalysisMode analysisMode = new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()));
- ScannerWsClient wsClient = new ScannerWsClient(WsClientFactories.getDefault().newClient(connector), false, analysisMode);
+ DefaultScannerWsClient wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connector), false, analysisMode);
userHome = temp.newFolder();
MapSettings settings = new MapSettings();
import org.sonar.api.batch.postjob.PostJob;
import org.sonar.api.batch.postjob.PostJobContext;
import org.sonar.api.batch.postjob.PostJobDescriptor;
-import org.sonar.scanner.postjob.DefaultPostJobDescriptor;
+import org.sonar.api.impl.sensor.DefaultPostJobDescriptor;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
public ExpectedException expectedException = ExpectedException.none();
private PluginFiles pluginFiles = mock(PluginFiles.class);
- private ScannerWsClient wsClient = mock(ScannerWsClient.class);
+ private DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
private ScannerPluginInstaller underTest = new ScannerPluginInstaller(pluginFiles, wsClient);
@Test
public void provide_client_with_default_settings() {
RawScannerProperties settings = new RawScannerProperties(new HashMap<>());
- ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
+ DefaultScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
assertThat(client).isNotNull();
assertThat(client.baseUrl()).isEqualTo("http://localhost:9000/");
props.put("sonar.ws.timeout", "42");
RawScannerProperties settings = new RawScannerProperties(props);
- ScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
+ DefaultScannerWsClient client = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), mock(System2.class));
assertThat(client).isNotNull();
HttpConnector httpConnector = (HttpConnector) client.wsConnector();
System2 system = mock(System2.class);
RawScannerProperties settings = new RawScannerProperties(new HashMap<>());
- ScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
- ScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
+ DefaultScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
+ DefaultScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap())), system);
assertThat(first).isSameAs(second);
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.bootstrap;
-
-import java.util.Collections;
-import java.util.List;
-import org.apache.commons.lang.StringUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.Mockito;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonarqube.ws.client.GetRequest;
-import org.sonarqube.ws.client.HttpException;
-import org.sonarqube.ws.client.MockWsResponse;
-import org.sonarqube.ws.client.WsClient;
-import org.sonarqube.ws.client.WsRequest;
-import org.sonarqube.ws.client.WsResponse;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ScannerWsClientTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- WsClient wsClient = mock(WsClient.class, Mockito.RETURNS_DEEP_STUBS);
-
- @Test
- public void log_and_profile_request_if_debug_level() {
- WsRequest request = newRequest();
- WsResponse response = newResponse().setRequestUrl("https://local/api/issues/search");
- when(wsClient.wsConnector().call(request)).thenReturn(response);
-
- logTester.setLevel(LoggerLevel.DEBUG);
- ScannerWsClient underTest = new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(
- new RawScannerProperties(Collections.emptyMap())));
-
- WsResponse result = underTest.call(request);
-
- // do not fail the execution -> interceptor returns the response
- assertThat(result).isSameAs(response);
-
- // check logs
- List<String> debugLogs = logTester.logs(LoggerLevel.DEBUG);
- assertThat(debugLogs).hasSize(1);
- assertThat(debugLogs.get(0)).contains("GET 200 https://local/api/issues/search | time=");
- }
-
- @Test
- public void create_error_msg_from_json() {
- String content = "{\"errors\":[{\"msg\":\"missing scan permission\"}, {\"msg\":\"missing another permission\"}]}";
- assertThat(ScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).isEqualTo("missing scan permission, missing another permission");
- }
-
- @Test
- public void create_error_msg_from_html() {
- String content = "<!DOCTYPE html><html>something</html>";
- assertThat(ScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).isEqualTo("HTTP code 400");
- }
-
- @Test
- public void create_error_msg_from_long_content() {
- String content = StringUtils.repeat("mystring", 1000);
- assertThat(ScannerWsClient.createErrorMessage(new HttpException("url", 400, content))).hasSize(15 + 128);
- }
-
- @Test
- public void fail_if_requires_credentials() {
- expectedException.expect(MessageException.class);
- expectedException
- .expectMessage("Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties sonar.login and sonar.password.");
-
- WsRequest request = newRequest();
- WsResponse response = newResponse().setCode(401);
- when(wsClient.wsConnector().call(request)).thenReturn(response);
-
- new ScannerWsClient(wsClient, false, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
- }
-
- @Test
- public void fail_if_credentials_are_not_valid() {
- expectedException.expect(MessageException.class);
- expectedException.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password.");
-
- WsRequest request = newRequest();
- WsResponse response = newResponse().setCode(401);
- when(wsClient.wsConnector().call(request)).thenReturn(response);
-
- new ScannerWsClient(wsClient, /* credentials are configured */true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
- }
-
- @Test
- public void fail_if_requires_permission() {
- expectedException.expect(MessageException.class);
- expectedException.expectMessage("You're not authorized to run analysis. Please contact the project administrator.");
-
- WsRequest request = newRequest();
- WsResponse response = newResponse()
- .setCode(403);
- when(wsClient.wsConnector().call(request)).thenReturn(response);
-
- new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
- }
-
- @Test
- public void fail_if_bad_request() {
- expectedException.expect(MessageException.class);
- expectedException.expectMessage("Boo! bad request! bad!");
-
- WsRequest request = newRequest();
- WsResponse response = newResponse()
- .setCode(400)
- .setContent("{\"errors\":[{\"msg\":\"Boo! bad request! bad!\"}]}");
- when(wsClient.wsConnector().call(request)).thenReturn(response);
-
- new ScannerWsClient(wsClient, true, new GlobalAnalysisMode(new RawScannerProperties(Collections.emptyMap()))).call(request);
- }
-
- private MockWsResponse newResponse() {
- return new MockWsResponse().setRequestUrl("https://local/api/issues/search");
- }
-
- private WsRequest newRequest() {
- return new GetRequest("api/issues/search");
- }
-}
package org.sonar.scanner.ci;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.index.ClonePart;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.ScannerReport.Duplicate;
import org.sonar.scanner.protocol.output.ScannerReport.Duplication;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.config.Configuration;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import org.mockito.MockitoAnnotations;
import org.sonar.duplications.block.Block;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.commons.lang.ObjectUtils.defaultIfNull;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.nio.charset.Charset;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultFileSystemTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- private DefaultFileSystem fs;
-
- private File basedir;
-
- @Before
- public void prepare() throws Exception {
- basedir = temp.newFolder();
- fs = new DefaultFileSystem(basedir.toPath());
- }
-
- @Test
- public void test_directories() throws Exception {
- assertThat(fs.baseDir()).isAbsolute().isDirectory().exists();
- assertThat(fs.baseDir().getCanonicalPath()).isEqualTo(basedir.getCanonicalPath());
-
- File workdir = temp.newFolder();
- fs.setWorkDir(workdir.toPath());
- assertThat(fs.workDir()).isAbsolute().isDirectory().exists();
- assertThat(fs.workDir().getCanonicalPath()).isEqualTo(workdir.getCanonicalPath());
- }
-
- @Test
- public void test_encoding() throws Exception {
- fs.setEncoding(Charset.forName("ISO-8859-1"));
- assertThat(fs.encoding()).isEqualTo(Charset.forName("ISO-8859-1"));
- }
-
- @Test
- public void add_languages() {
- assertThat(fs.languages()).isEmpty();
-
- fs.add(new TestInputFileBuilder("foo", "src/Foo.php").setLanguage("php").build());
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
-
- assertThat(fs.languages()).containsOnly("java", "php");
- }
-
- @Test
- public void files() {
- assertThat(fs.inputFiles(fs.predicates().all())).isEmpty();
-
- fs.add(new TestInputFileBuilder("foo", "src/Foo.php").setLanguage("php").build());
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
- fs.add(new TestInputFileBuilder("foo", "src/Baz.java").setLanguage("java").build());
-
- // no language
- fs.add(new TestInputFileBuilder("foo", "src/readme.txt").build());
-
- assertThat(fs.inputFile(fs.predicates().hasRelativePath("src/Bar.java"))).isNotNull();
- assertThat(fs.inputFile(fs.predicates().hasRelativePath("does/not/exist"))).isNull();
-
- assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "src/Bar.java").getAbsolutePath()))).isNotNull();
- assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "does/not/exist").getAbsolutePath()))).isNull();
- assertThat(fs.inputFile(fs.predicates().hasAbsolutePath(new File(basedir, "../src/Bar.java").getAbsolutePath()))).isNull();
-
- assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "src/Bar.java").toURI()))).isNotNull();
- assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "does/not/exist").toURI()))).isNull();
- assertThat(fs.inputFile(fs.predicates().hasURI(new File(basedir, "../src/Bar.java").toURI()))).isNull();
-
- assertThat(fs.files(fs.predicates().all())).hasSize(4);
- assertThat(fs.files(fs.predicates().hasLanguage("java"))).hasSize(2);
- assertThat(fs.files(fs.predicates().hasLanguage("cobol"))).isEmpty();
-
- assertThat(fs.hasFiles(fs.predicates().all())).isTrue();
- assertThat(fs.hasFiles(fs.predicates().hasLanguage("java"))).isTrue();
- assertThat(fs.hasFiles(fs.predicates().hasLanguage("cobol"))).isFalse();
-
- assertThat(fs.inputFiles(fs.predicates().all())).hasSize(4);
- assertThat(fs.inputFiles(fs.predicates().hasLanguage("php"))).hasSize(1);
- assertThat(fs.inputFiles(fs.predicates().hasLanguage("java"))).hasSize(2);
- assertThat(fs.inputFiles(fs.predicates().hasLanguage("cobol"))).isEmpty();
-
- assertThat(fs.languages()).containsOnly("java", "php");
- }
-
- @Test
- public void input_file_returns_null_if_file_not_found() {
- assertThat(fs.inputFile(fs.predicates().hasRelativePath("src/Bar.java"))).isNull();
- assertThat(fs.inputFile(fs.predicates().hasLanguage("cobol"))).isNull();
- }
-
- @Test
- public void input_file_fails_if_too_many_results() {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("expected one element");
-
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
- fs.add(new TestInputFileBuilder("foo", "src/Baz.java").setLanguage("java").build());
-
- fs.inputFile(fs.predicates().all());
- }
-
- @Test
- public void input_file_supports_non_indexed_predicates() {
- fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
-
- // it would fail if more than one java file
- assertThat(fs.inputFile(fs.predicates().hasLanguage("java"))).isNotNull();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultInputDirTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void test() throws Exception {
- File baseDir = temp.newFolder();
- DefaultInputDir inputDir = new DefaultInputDir("ABCDE", "src")
- .setModuleBaseDir(baseDir.toPath());
-
- assertThat(inputDir.key()).isEqualTo("ABCDE:src");
- assertThat(inputDir.file().getAbsolutePath()).isEqualTo(new File(baseDir, "src").getAbsolutePath());
- assertThat(inputDir.relativePath()).isEqualTo("src");
- assertThat(new File(inputDir.relativePath())).isRelative();
- assertThat(inputDir.absolutePath()).endsWith("src");
- assertThat(new File(inputDir.absolutePath())).isAbsolute();
- }
-
- @Test
- public void testEqualsAndHashCode() throws Exception {
- DefaultInputDir inputDir1 = new DefaultInputDir("ABCDE", "src");
-
- DefaultInputDir inputDir2 = new DefaultInputDir("ABCDE", "src");
-
- assertThat(inputDir1.equals(inputDir1)).isTrue();
- assertThat(inputDir1.equals(inputDir2)).isTrue();
- assertThat(inputDir1.equals("foo")).isFalse();
-
- assertThat(inputDir1.hashCode()).isEqualTo(63545559);
-
- assertThat(inputDir1.toString()).contains("[moduleKey=ABCDE, relative=src, basedir=null");
-
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.StringReader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.stream.Collectors;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.fs.internal.Metadata;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-
-public class DefaultInputFileTest {
-
- private static final String PROJECT_RELATIVE_PATH = "module1/src/Foo.php";
- private static final String MODULE_RELATIVE_PATH = "src/Foo.php";
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private DefaultIndexedFile indexedFile;
-
- private Path baseDir;
- private SensorStrategy sensorStrategy;
-
- @Before
- public void prepare() throws IOException {
- baseDir = temp.newFolder().toPath();
- sensorStrategy = new SensorStrategy();
- indexedFile = new DefaultIndexedFile(baseDir.resolve(PROJECT_RELATIVE_PATH), "ABCDE", PROJECT_RELATIVE_PATH, MODULE_RELATIVE_PATH, InputFile.Type.TEST, "php", 0,
- sensorStrategy);
- }
-
- @Test
- public void test() throws Exception {
-
- Metadata metadata = new Metadata(42, 42, "", new int[0], new int[0], 10);
- DefaultInputFile inputFile = new DefaultInputFile(indexedFile, (f) -> f.setMetadata(metadata))
- .setStatus(InputFile.Status.ADDED)
- .setCharset(StandardCharsets.ISO_8859_1);
-
- assertThat(inputFile.absolutePath()).endsWith("Foo.php");
- assertThat(inputFile.filename()).isEqualTo("Foo.php");
- assertThat(inputFile.uri()).hasPath(baseDir.resolve(PROJECT_RELATIVE_PATH).toUri().getPath());
- assertThat(new File(inputFile.absolutePath())).isAbsolute();
- assertThat(inputFile.language()).isEqualTo("php");
- assertThat(inputFile.status()).isEqualTo(InputFile.Status.ADDED);
- assertThat(inputFile.type()).isEqualTo(InputFile.Type.TEST);
- assertThat(inputFile.lines()).isEqualTo(42);
- assertThat(inputFile.charset()).isEqualTo(StandardCharsets.ISO_8859_1);
-
- assertThat(inputFile.getModuleRelativePath()).isEqualTo(MODULE_RELATIVE_PATH);
- assertThat(inputFile.getProjectRelativePath()).isEqualTo(PROJECT_RELATIVE_PATH);
-
- sensorStrategy.setGlobal(false);
- assertThat(inputFile.relativePath()).isEqualTo(MODULE_RELATIVE_PATH);
- assertThat(new File(inputFile.relativePath())).isRelative();
- sensorStrategy.setGlobal(true);
- assertThat(inputFile.relativePath()).isEqualTo(PROJECT_RELATIVE_PATH);
- assertThat(new File(inputFile.relativePath())).isRelative();
- }
-
- @Test
- public void test_content() throws IOException {
- Path testFile = baseDir.resolve(PROJECT_RELATIVE_PATH);
- Files.createDirectories(testFile.getParent());
- String content = "test é string";
- Files.write(testFile, content.getBytes(StandardCharsets.ISO_8859_1));
-
- assertThat(Files.readAllLines(testFile, StandardCharsets.ISO_8859_1).get(0)).hasSize(content.length());
-
- Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10);
-
- DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata))
- .setStatus(InputFile.Status.ADDED)
- .setCharset(StandardCharsets.ISO_8859_1);
-
- assertThat(inputFile.contents()).isEqualTo(content);
- try (InputStream inputStream = inputFile.inputStream()) {
- String result = new BufferedReader(new InputStreamReader(inputStream, inputFile.charset())).lines().collect(Collectors.joining());
- assertThat(result).isEqualTo(content);
- }
-
- }
-
- @Test
- public void test_content_exclude_bom() throws IOException {
- Path testFile = baseDir.resolve(PROJECT_RELATIVE_PATH);
- Files.createDirectories(testFile.getParent());
- try (BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(testFile.toFile()), StandardCharsets.UTF_8))) {
- out.write('\ufeff');
- }
- String content = "test é string €";
- Files.write(testFile, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
-
- assertThat(Files.readAllLines(testFile, StandardCharsets.UTF_8).get(0)).hasSize(content.length() + 1);
-
- Metadata metadata = new Metadata(42, 30, "", new int[0], new int[0], 10);
-
- DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> f.setMetadata(metadata))
- .setStatus(InputFile.Status.ADDED)
- .setCharset(StandardCharsets.UTF_8);
-
- assertThat(inputFile.contents()).isEqualTo(content);
- try (InputStream inputStream = inputFile.inputStream()) {
- String result = new BufferedReader(new InputStreamReader(inputStream, inputFile.charset())).lines().collect(Collectors.joining());
- assertThat(result).isEqualTo(content);
- }
-
- }
-
- @Test
- public void test_equals_and_hashcode() throws Exception {
- DefaultInputFile f1 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
- DefaultInputFile f1a = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
- DefaultInputFile f2 = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), "src/Bar.php", null), (f) -> mock(Metadata.class));
-
- assertThat(f1).isEqualTo(f1);
- assertThat(f1).isEqualTo(f1a);
- assertThat(f1).isNotEqualTo(f2);
- assertThat(f1.equals("foo")).isFalse();
- assertThat(f1.equals(null)).isFalse();
-
- assertThat(f1.hashCode()).isEqualTo(f1.hashCode());
- assertThat(f1.hashCode()).isEqualTo(f1a.hashCode());
- }
-
- @Test
- public void test_toString() throws Exception {
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), (f) -> mock(Metadata.class));
- assertThat(file.toString()).isEqualTo(MODULE_RELATIVE_PATH);
- }
-
- @Test
- public void checkValidPointer() {
- Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
- assertThat(file.newPointer(1, 0).line()).isEqualTo(1);
- assertThat(file.newPointer(1, 0).lineOffset()).isEqualTo(0);
- // Don't fail
- file.newPointer(1, 9);
- file.newPointer(2, 0);
- file.newPointer(2, 5);
-
- try {
- file.newPointer(0, 1);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("0 is not a valid line for a file");
- }
- try {
- file.newPointer(3, 1);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("3 is not a valid line for pointer. File src/Foo.php has 2 line(s)");
- }
- try {
- file.newPointer(1, -1);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("-1 is not a valid line offset for a file");
- }
- try {
- file.newPointer(1, 10);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("10 is not a valid line offset for pointer. File src/Foo.php has 9 character(s) at line 1");
- }
- }
-
- @Test
- public void checkValidPointerUsingGlobalOffset() {
- Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {8, 15}, 16);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
- assertThat(file.newPointer(0).line()).isEqualTo(1);
- assertThat(file.newPointer(0).lineOffset()).isEqualTo(0);
-
- assertThat(file.newPointer(9).line()).isEqualTo(1);
- // Ignore eol characters
- assertThat(file.newPointer(9).lineOffset()).isEqualTo(8);
-
- assertThat(file.newPointer(10).line()).isEqualTo(2);
- assertThat(file.newPointer(10).lineOffset()).isEqualTo(0);
-
- assertThat(file.newPointer(15).line()).isEqualTo(2);
- assertThat(file.newPointer(15).lineOffset()).isEqualTo(5);
-
- assertThat(file.newPointer(16).line()).isEqualTo(2);
- // Ignore eol characters
- assertThat(file.newPointer(16).lineOffset()).isEqualTo(5);
-
- try {
- file.newPointer(-1);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("-1 is not a valid offset for a file");
- }
-
- try {
- file.newPointer(17);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("17 is not a valid offset for file src/Foo.php. Max offset is 16");
- }
- }
-
- @Test
- public void checkValidRange() {
- Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde"));
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
-
- assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 1)).start().line()).isEqualTo(1);
- // Don't fail
- file.newRange(file.newPointer(1, 0), file.newPointer(1, 1));
- file.newRange(file.newPointer(1, 0), file.newPointer(1, 9));
- file.newRange(file.newPointer(1, 0), file.newPointer(2, 0));
- assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(2, 5))).isEqualTo(file.newRange(0, 15));
-
- try {
- file.newRange(file.newPointer(1, 0), file.newPointer(1, 0));
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("Start pointer [line=1, lineOffset=0] should be before end pointer [line=1, lineOffset=0]");
- }
- try {
- file.newRange(file.newPointer(1, 0), file.newPointer(1, 10));
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("10 is not a valid line offset for pointer. File src/Foo.php has 9 character(s) at line 1");
- }
- }
-
- @Test
- public void selectLine() {
- Metadata metadata = new FileMetadata().readMetadata(new StringReader("bla bla a\nabcde\n\nabc"));
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
-
- assertThat(file.selectLine(1).start().line()).isEqualTo(1);
- assertThat(file.selectLine(1).start().lineOffset()).isEqualTo(0);
- assertThat(file.selectLine(1).end().line()).isEqualTo(1);
- assertThat(file.selectLine(1).end().lineOffset()).isEqualTo(9);
-
- // Don't fail when selecting empty line
- assertThat(file.selectLine(3).start().line()).isEqualTo(3);
- assertThat(file.selectLine(3).start().lineOffset()).isEqualTo(0);
- assertThat(file.selectLine(3).end().line()).isEqualTo(3);
- assertThat(file.selectLine(3).end().lineOffset()).isEqualTo(0);
-
- try {
- file.selectLine(5);
- fail();
- } catch (Exception e) {
- assertThat(e).hasMessage("5 is not a valid line for pointer. File src/Foo.php has 4 line(s)");
- }
- }
-
- @Test
- public void checkValidRangeUsingGlobalOffset() {
- Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
- TextRange newRange = file.newRange(10, 13);
- assertThat(newRange.start().line()).isEqualTo(2);
- assertThat(newRange.start().lineOffset()).isEqualTo(0);
- assertThat(newRange.end().line()).isEqualTo(2);
- assertThat(newRange.end().lineOffset()).isEqualTo(3);
- }
-
- @Test
- public void testRangeOverlap() {
- Metadata metadata = new Metadata(2, 2, "", new int[] {0, 10}, new int[] {9, 15}, 16);
- DefaultInputFile file = new DefaultInputFile(new DefaultIndexedFile("ABCDE", Paths.get("module"), MODULE_RELATIVE_PATH, null), f -> f.setMetadata(metadata));
- // Don't fail
- assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)))).isTrue();
- assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isTrue();
- assertThat(file.newRange(file.newPointer(1, 0), file.newPointer(1, 1)).overlap(file.newRange(file.newPointer(1, 1), file.newPointer(1, 2)))).isFalse();
- assertThat(file.newRange(file.newPointer(1, 2), file.newPointer(1, 3)).overlap(file.newRange(file.newPointer(1, 0), file.newPointer(1, 2)))).isFalse();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultInputModuleTest {
-
- private static final String FILE_1 = "file1";
- private static final String TEST_1 = "test1";
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void check_getters() throws IOException {
- ProjectDefinition def = ProjectDefinition.create();
- def.setKey("moduleKey");
- File baseDir = temp.newFolder();
- Path src = baseDir.toPath().resolve(FILE_1);
- Files.createFile(src);
- Path test = baseDir.toPath().resolve(TEST_1);
- Files.createFile(test);
- def.setBaseDir(baseDir);
- File workDir = temp.newFolder();
- def.setWorkDir(workDir);
- def.setSources(FILE_1);
- def.setTests(TEST_1);
- DefaultInputModule module = new DefaultInputModule(def);
-
- assertThat(module.key()).isEqualTo("moduleKey");
- assertThat(module.definition()).isEqualTo(def);
- assertThat(module.getBranch()).isNull();
- assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
- assertThat(module.getKeyWithBranch()).isEqualTo("moduleKey");
- assertThat(module.getWorkDir()).isEqualTo(workDir.toPath());
- assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
- assertThat(module.getSourceDirsOrFiles().get()).containsExactlyInAnyOrder(src);
- assertThat(module.getTestDirsOrFiles().get()).containsExactlyInAnyOrder(test);
- assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
-
- assertThat(module.isFile()).isFalse();
- }
-
- @Test
- public void no_sources() throws IOException {
- ProjectDefinition def = ProjectDefinition.create();
- def.setKey("moduleKey");
- File baseDir = temp.newFolder();
- Path src = baseDir.toPath().resolve(FILE_1);
- Files.createFile(src);
- Path test = baseDir.toPath().resolve(TEST_1);
- Files.createFile(test);
- def.setBaseDir(baseDir);
- File workDir = temp.newFolder();
- def.setWorkDir(workDir);
- DefaultInputModule module = new DefaultInputModule(def);
-
- assertThat(module.key()).isEqualTo("moduleKey");
- assertThat(module.definition()).isEqualTo(def);
- assertThat(module.getBranch()).isNull();
- assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
- assertThat(module.getKeyWithBranch()).isEqualTo("moduleKey");
- assertThat(module.getWorkDir()).isEqualTo(workDir.toPath());
- assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
- assertThat(module.getSourceDirsOrFiles()).isNotPresent();
- assertThat(module.getTestDirsOrFiles()).isNotPresent();
- assertThat(module.getEncoding()).isEqualTo(Charset.defaultCharset());
-
- assertThat(module.isFile()).isFalse();
- }
-
- @Test
- public void working_directory_should_be_hidden() throws IOException {
- ProjectDefinition def = ProjectDefinition.create();
- File workDir = temp.newFolder(".sonar");
- def.setWorkDir(workDir);
- File baseDir = temp.newFolder();
- def.setBaseDir(baseDir);
- DefaultInputModule module = new DefaultInputModule(def);
- assertThat(workDir.isHidden()).isTrue();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultInputProjectTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void testGetters() throws IOException {
- ProjectDefinition def = ProjectDefinition.create();
- def.setKey("projectKey");
- def.setName("projectName");
- File baseDir = temp.newFolder();
- def.setBaseDir(baseDir);
- def.setDescription("desc");
- File workDir = temp.newFolder();
- def.setWorkDir(workDir);
- def.setSources("file1");
- def.setTests("test1");
- AbstractProjectOrModule project = new DefaultInputProject(def);
-
- assertThat(project.key()).isEqualTo("projectKey");
- assertThat(project.getName()).isEqualTo("projectName");
- assertThat(project.getOriginalName()).isEqualTo("projectName");
- assertThat(project.definition()).isEqualTo(def);
- assertThat(project.getBranch()).isNull();
- assertThat(project.getBaseDir()).isEqualTo(baseDir.toPath());
- assertThat(project.getKeyWithBranch()).isEqualTo("projectKey");
- assertThat(project.getDescription()).isEqualTo("desc");
- assertThat(project.getWorkDir()).isEqualTo(workDir.toPath());
- assertThat(project.getEncoding()).isEqualTo(Charset.defaultCharset());
-
- assertThat(project.properties()).hasSize(5);
-
- assertThat(project.isFile()).isFalse();
- }
-
- @Test
- public void testEncoding() throws IOException {
- ProjectDefinition def = ProjectDefinition.create();
- def.setKey("projectKey");
- def.setName("projectName");
- File baseDir = temp.newFolder();
- def.setBaseDir(baseDir);
- def.setProjectVersion("version");
- def.setDescription("desc");
- File workDir = temp.newFolder();
- def.setWorkDir(workDir);
- def.setSources("file1");
- def.setProperty("sonar.sourceEncoding", "UTF-16");
- AbstractProjectOrModule project = new DefaultInputProject(def);
-
- assertThat(project.getEncoding()).isEqualTo(StandardCharsets.UTF_16);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import javax.annotation.Nullable;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.internal.Metadata;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-
-import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-
-public class FileMetadataTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Test
- public void empty_file() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.touch(tempFile);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(1);
- assertThat(metadata.nonBlankLines()).isEqualTo(0);
- assertThat(metadata.hash()).isNotEmpty();
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(0);
- assertThat(metadata.isEmpty()).isTrue();
- }
-
- @Test
- public void windows_without_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\r\nbar\r\nbaz", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(3);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 8, 13);
- assertThat(metadata.isEmpty()).isFalse();
- }
-
- @Test
- public void read_with_wrong_encoding() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "marker´s\n", Charset.forName("cp1252"));
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(2);
- assertThat(metadata.hash()).isEqualTo(md5Hex("marker\ufffds\n"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 9);
- }
-
- @Test
- public void non_ascii_utf_8() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "föo\r\nbà r\r\n\u1D11Ebaßz\r\n", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbà r\n\u1D11Ebaßz\n"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18);
- }
-
- @Test
- public void non_ascii_utf_16() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "föo\r\nbà r\r\n\u1D11Ebaßz\r\n", StandardCharsets.UTF_16, true);
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_16, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("föo\nbà r\n\u1D11Ebaßz\n".getBytes(StandardCharsets.UTF_8)));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 5, 10, 18);
- }
-
- @Test
- public void unix_without_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\nbar\nbaz", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(3);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11);
- assertThat(metadata.isEmpty()).isFalse();
- }
-
- @Test
- public void unix_with_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\nbar\nbaz\n", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12);
- }
-
- @Test
- public void mac_without_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\rbar\rbaz", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(3);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11);
- }
-
- @Test
- public void mac_with_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\rbar\rbaz\r", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 8, 12);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 11, 12);
- }
-
- @Test
- public void mix_of_newlines_with_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\nbar\r\nbaz\n", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz\n"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9, 13);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12, 13);
- }
-
- @Test
- public void several_new_lines() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\n\n\nbar", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(2);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\n\n\nbar"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 5, 6);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 4, 5, 9);
- }
-
- @Test
- public void mix_of_newlines_without_latest_eol() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "foo\nbar\r\nbaz", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(3);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("foo\nbar\nbaz"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 4, 9);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(3, 7, 12);
- }
-
- @Test
- public void start_with_newline() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "\nfoo\nbar\r\nbaz", StandardCharsets.UTF_8, true);
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(tempFile), StandardCharsets.UTF_8, tempFile.getName());
- assertThat(metadata.lines()).isEqualTo(4);
- assertThat(metadata.nonBlankLines()).isEqualTo(3);
- assertThat(metadata.hash()).isEqualTo(md5Hex("\nfoo\nbar\nbaz"));
- assertThat(metadata.originalLineStartOffsets()).containsOnly(0, 1, 5, 10);
- assertThat(metadata.originalLineEndOffsets()).containsOnly(0, 4, 8, 13);
- }
-
- @Test
- public void ignore_whitespace_when_computing_line_hashes() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, " foo\nb ar\r\nbaz \t", StandardCharsets.UTF_8, true);
-
- DefaultInputFile f = new TestInputFileBuilder("foo", tempFile.getName())
- .setModuleBaseDir(tempFile.getParentFile().toPath())
- .setCharset(StandardCharsets.UTF_8)
- .build();
- FileMetadata.computeLineHashesForIssueTracking(f, new FileMetadata.LineHashConsumer() {
-
- @Override
- public void consume(int lineIdx, @Nullable byte[] hash) {
- switch (lineIdx) {
- case 1:
- assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("foo"));
- break;
- case 2:
- assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("bar"));
- break;
- case 3:
- assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("baz"));
- break;
- default:
- fail("Invalid line");
- }
- }
- });
- }
-
- @Test
- public void dont_fail_on_empty_file() throws Exception {
- File tempFile = temp.newFile();
- FileUtils.write(tempFile, "", StandardCharsets.UTF_8, true);
-
- DefaultInputFile f = new TestInputFileBuilder("foo", tempFile.getName())
- .setModuleBaseDir(tempFile.getParentFile().toPath())
- .setCharset(StandardCharsets.UTF_8)
- .build();
- FileMetadata.computeLineHashesForIssueTracking(f, new FileMetadata.LineHashConsumer() {
-
- @Override
- public void consume(int lineIdx, @Nullable byte[] hash) {
- switch (lineIdx) {
- case 1:
- assertThat(hash).isNull();
- break;
- default:
- fail("Invalid line");
- }
- }
- });
- }
-
- @Test
- public void line_feed_is_included_into_hash() throws Exception {
- File file1 = temp.newFile();
- FileUtils.write(file1, "foo\nbar\n", StandardCharsets.UTF_8, true);
-
- // same as file1, except an additional return carriage
- File file1a = temp.newFile();
- FileUtils.write(file1a, "foo\r\nbar\n", StandardCharsets.UTF_8, true);
-
- File file2 = temp.newFile();
- FileUtils.write(file2, "foo\nbar", StandardCharsets.UTF_8, true);
-
- String hash1 = new FileMetadata().readMetadata(new FileInputStream(file1), StandardCharsets.UTF_8, file1.getName()).hash();
- String hash1a = new FileMetadata().readMetadata(new FileInputStream(file1a), StandardCharsets.UTF_8, file1a.getName()).hash();
- String hash2 = new FileMetadata().readMetadata(new FileInputStream(file2), StandardCharsets.UTF_8, file2.getName()).hash();
-
- assertThat(hash1).isEqualTo(hash1a);
- assertThat(hash1).isNotEqualTo(hash2);
- }
-
- @Test
- public void binary_file_with_unmappable_character() throws Exception {
- File woff = new File(this.getClass().getResource("glyphicons-halflings-regular.woff").toURI());
-
- Metadata metadata = new FileMetadata().readMetadata(new FileInputStream(woff), StandardCharsets.UTF_8, woff.getAbsolutePath());
-
- assertThat(metadata.lines()).isEqualTo(135);
- assertThat(metadata.nonBlankLines()).isEqualTo(133);
- assertThat(metadata.hash()).isNotEmpty();
-
- assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains("Invalid character encountered in file");
- assertThat(logTester.logs(LoggerLevel.WARN).get(0)).contains(
- "glyphicons-halflings-regular.woff at line 1 for encoding UTF-8. Please fix file content or configure the encoding to be used using property 'sonar.sourceEncoding'.");
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.api.batch.fs.InputFile.Type;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class TestInputFileBuilderTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void setContent() throws IOException {
- DefaultInputFile file = TestInputFileBuilder.create("module", "invalidPath")
- .setContents("my content")
- .setCharset(StandardCharsets.UTF_8)
- .build();
- assertThat(file.contents()).isEqualTo("my content");
- assertThat(IOUtils.toString(file.inputStream())).isEqualTo("my content");
- }
-
- @Test
- public void testGetters() {
- DefaultInputFile file = TestInputFileBuilder.create("module", new File("baseDir"), new File("baseDir", "path"))
- .setStatus(Status.SAME)
- .setType(Type.MAIN)
- .build();
-
- assertThat(file.type()).isEqualTo(Type.MAIN);
- assertThat(file.status()).isEqualTo(Status.SAME);
- assertThat(file.isPublished()).isTrue();
- assertThat(file.type()).isEqualTo(Type.MAIN);
- assertThat(file.relativePath()).isEqualTo("path");
- assertThat(file.absolutePath()).isEqualTo("baseDir/path");
-
- }
-
- @Test
- public void testCreateInputModule() throws IOException {
- File baseDir = temp.newFolder();
- AbstractProjectOrModule module = TestInputFileBuilder.newDefaultInputModule("key", baseDir);
- assertThat(module.key()).isEqualTo("key");
- assertThat(module.getBaseDir()).isEqualTo(baseDir.toPath());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.charhandler;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class IntArrayListTest {
-
- @Test
- public void addElements() {
- IntArrayList list = new IntArrayList();
- assertThat(list.trimAndGet()).isEmpty();
- list.add(1);
- list.add(2);
- assertThat(list.trimAndGet()).containsExactly(1, 2);
- }
-
- @Test
- public void trimIfNeeded() {
- IntArrayList list = new IntArrayList();
- list.add(1);
- list.add(2);
- assertThat(list.trimAndGet()).isSameAs(list.trimAndGet());
- }
-
- @Test
- public void grow() {
- // Default capacity is 10
- IntArrayList list = new IntArrayList();
- for (int i = 1; i <= 11; i++) {
- list.add(i);
- }
- assertThat(list.trimAndGet()).hasSize(11);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.junit.Test;
-import org.sonar.api.batch.fs.FilePredicate;
-
-import java.util.Arrays;
-import org.sonar.api.batch.fs.internal.PathPattern;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class AndPredicateTest {
-
- @Test
- public void flattenNestedAnd() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("foo3/**"));
- FilePredicate andPredicate = AndPredicate.create(Arrays.<FilePredicate>asList(pathPatternPredicate1,
- AndPredicate.create(Arrays.<FilePredicate>asList(pathPatternPredicate2, pathPatternPredicate3))));
- assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2, pathPatternPredicate3);
- }
-
- @Test
- public void sortPredicatesByPriority() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- RelativePathPredicate relativePathPredicate = new RelativePathPredicate("foo");
- FilePredicate andPredicate = AndPredicate.create(Arrays.<FilePredicate>asList(pathPatternPredicate1,
- relativePathPredicate, pathPatternPredicate2));
- assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(relativePathPredicate, pathPatternPredicate1, pathPatternPredicate2);
- }
-
- @Test
- public void simplifyAndExpressionsWhenEmpty() {
- FilePredicate andPredicate = AndPredicate.create(Arrays.<FilePredicate>asList());
- assertThat(andPredicate).isEqualTo(TruePredicate.TRUE);
- }
-
- @Test
- public void simplifyAndExpressionsWhenTrue() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- FilePredicate andPredicate = AndPredicate.create(Arrays.<FilePredicate>asList(pathPatternPredicate1,
- TruePredicate.TRUE, pathPatternPredicate2));
- assertThat(((AndPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2);
- }
-
- @Test
- public void simplifyAndExpressionsWhenFalse() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- FilePredicate andPredicate = AndPredicate.create(Arrays.<FilePredicate>asList(pathPatternPredicate1,
- FalsePredicate.FALSE, pathPatternPredicate2));
- assertThat(andPredicate).isEqualTo(FalsePredicate.FALSE);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.fs.FilePredicate;
-import org.sonar.api.batch.fs.FilePredicates;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultFilePredicatesTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private Path moduleBasePath;
-
- @Before
- public void setUp() throws IOException {
- moduleBasePath = temp.newFolder().toPath();
- }
-
- InputFile javaFile;
- FilePredicates predicates;
-
- @Before
- public void before() throws IOException {
- predicates = new DefaultFilePredicates(temp.newFolder().toPath());
- javaFile = new TestInputFileBuilder("foo", "src/main/java/struts/Action.java")
- .setModuleBaseDir(moduleBasePath)
- .setLanguage("java")
- .setStatus(Status.SAME)
- .build();
-
- }
-
- @Test
- public void all() {
- assertThat(predicates.all().apply(javaFile)).isTrue();
- }
-
- @Test
- public void none() {
- assertThat(predicates.none().apply(javaFile)).isFalse();
- }
-
- @Test
- public void matches_inclusion_pattern() {
- assertThat(predicates.matchesPathPattern("src/main/**/Action.java").apply(javaFile)).isTrue();
- assertThat(predicates.matchesPathPattern("Action.java").apply(javaFile)).isFalse();
- assertThat(predicates.matchesPathPattern("src/**/*.php").apply(javaFile)).isFalse();
- }
-
- @Test
- public void matches_inclusion_patterns() {
- assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isTrue();
- assertThat(predicates.matchesPathPatterns(new String[] {}).apply(javaFile)).isTrue();
- assertThat(predicates.matchesPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isFalse();
- }
-
- @Test
- public void does_not_match_exclusion_pattern() {
- assertThat(predicates.doesNotMatchPathPattern("src/main/**/Action.java").apply(javaFile)).isFalse();
- assertThat(predicates.doesNotMatchPathPattern("Action.java").apply(javaFile)).isTrue();
- assertThat(predicates.doesNotMatchPathPattern("src/**/*.php").apply(javaFile)).isTrue();
- }
-
- @Test
- public void does_not_match_exclusion_patterns() {
- assertThat(predicates.doesNotMatchPathPatterns(new String[] {}).apply(javaFile)).isTrue();
- assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/**/*.php"}).apply(javaFile)).isTrue();
- assertThat(predicates.doesNotMatchPathPatterns(new String[] {"src/other/**.java", "src/main/**/Action.java"}).apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_relative_path() {
- assertThat(predicates.hasRelativePath("src/main/java/struts/Action.java").apply(javaFile)).isTrue();
- assertThat(predicates.hasRelativePath("src/main/java/struts/Other.java").apply(javaFile)).isFalse();
-
- // path is normalized
- assertThat(predicates.hasRelativePath("src/main/java/../java/struts/Action.java").apply(javaFile)).isTrue();
-
- assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\Action.java").apply(javaFile)).isTrue();
- assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\Other.java").apply(javaFile)).isFalse();
- assertThat(predicates.hasRelativePath("src\\main\\java\\struts\\..\\struts\\Action.java").apply(javaFile)).isTrue();
- }
-
- @Test
- public void has_absolute_path() throws Exception {
- String path = javaFile.file().getAbsolutePath();
- assertThat(predicates.hasAbsolutePath(path).apply(javaFile)).isTrue();
- assertThat(predicates.hasAbsolutePath(path.replaceAll("/", "\\\\")).apply(javaFile)).isTrue();
-
- assertThat(predicates.hasAbsolutePath(temp.newFile().getAbsolutePath()).apply(javaFile)).isFalse();
- assertThat(predicates.hasAbsolutePath("src/main/java/struts/Action.java").apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_uri() throws Exception {
- URI uri = javaFile.uri();
- assertThat(predicates.hasURI(uri).apply(javaFile)).isTrue();
-
- assertThat(predicates.hasURI(temp.newFile().toURI()).apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_path() throws Exception {
- // is relative path
- assertThat(predicates.hasPath("src/main/java/struts/Action.java").apply(javaFile)).isTrue();
- assertThat(predicates.hasPath("src/main/java/struts/Other.java").apply(javaFile)).isFalse();
-
- // is absolute path
- String path = javaFile.file().getAbsolutePath();
- assertThat(predicates.hasAbsolutePath(path).apply(javaFile)).isTrue();
- assertThat(predicates.hasPath(temp.newFile().getAbsolutePath()).apply(javaFile)).isFalse();
- }
-
- @Test
- public void is_file() throws Exception {
- // relative file
- assertThat(predicates.is(new File(javaFile.relativePath())).apply(javaFile)).isTrue();
-
- // absolute file
- assertThat(predicates.is(javaFile.file()).apply(javaFile)).isTrue();
- assertThat(predicates.is(javaFile.file().getAbsoluteFile()).apply(javaFile)).isTrue();
- assertThat(predicates.is(new File(javaFile.file().toURI())).apply(javaFile)).isTrue();
- assertThat(predicates.is(temp.newFile()).apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_language() {
- assertThat(predicates.hasLanguage("java").apply(javaFile)).isTrue();
- assertThat(predicates.hasLanguage("php").apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_languages() {
- assertThat(predicates.hasLanguages(Arrays.asList("java", "php")).apply(javaFile)).isTrue();
- assertThat(predicates.hasLanguages(Arrays.asList("cobol", "php")).apply(javaFile)).isFalse();
- assertThat(predicates.hasLanguages(Collections.<String>emptyList()).apply(javaFile)).isTrue();
- }
-
- @Test
- public void has_type() {
- assertThat(predicates.hasType(InputFile.Type.MAIN).apply(javaFile)).isTrue();
- assertThat(predicates.hasType(InputFile.Type.TEST).apply(javaFile)).isFalse();
- }
-
- @Test
- public void has_status() {
- assertThat(predicates.hasAnyStatus().apply(javaFile)).isTrue();
- assertThat(predicates.hasStatus(InputFile.Status.SAME).apply(javaFile)).isTrue();
- assertThat(predicates.hasStatus(InputFile.Status.ADDED).apply(javaFile)).isFalse();
- }
-
- @Test
- public void not() {
- assertThat(predicates.not(predicates.hasType(InputFile.Type.MAIN)).apply(javaFile)).isFalse();
- assertThat(predicates.not(predicates.hasType(InputFile.Type.TEST)).apply(javaFile)).isTrue();
- }
-
- @Test
- public void and() {
- // empty
- assertThat(predicates.and().apply(javaFile)).isTrue();
- assertThat(predicates.and(new FilePredicate[0]).apply(javaFile)).isTrue();
- assertThat(predicates.and(Collections.<FilePredicate>emptyList()).apply(javaFile)).isTrue();
-
- // two arguments
- assertThat(predicates.and(predicates.all(), predicates.all()).apply(javaFile)).isTrue();
- assertThat(predicates.and(predicates.all(), predicates.none()).apply(javaFile)).isFalse();
- assertThat(predicates.and(predicates.none(), predicates.all()).apply(javaFile)).isFalse();
-
- // collection
- assertThat(predicates.and(Arrays.asList(predicates.all(), predicates.all())).apply(javaFile)).isTrue();
- assertThat(predicates.and(Arrays.asList(predicates.all(), predicates.none())).apply(javaFile)).isFalse();
-
- // array
- assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
- assertThat(predicates.and(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isFalse();
- }
-
- @Test
- public void or() {
- // empty
- assertThat(predicates.or().apply(javaFile)).isTrue();
- assertThat(predicates.or(new FilePredicate[0]).apply(javaFile)).isTrue();
- assertThat(predicates.or(Collections.<FilePredicate>emptyList()).apply(javaFile)).isTrue();
-
- // two arguments
- assertThat(predicates.or(predicates.all(), predicates.all()).apply(javaFile)).isTrue();
- assertThat(predicates.or(predicates.all(), predicates.none()).apply(javaFile)).isTrue();
- assertThat(predicates.or(predicates.none(), predicates.all()).apply(javaFile)).isTrue();
- assertThat(predicates.or(predicates.none(), predicates.none()).apply(javaFile)).isFalse();
-
- // collection
- assertThat(predicates.or(Arrays.asList(predicates.all(), predicates.all())).apply(javaFile)).isTrue();
- assertThat(predicates.or(Arrays.asList(predicates.all(), predicates.none())).apply(javaFile)).isTrue();
- assertThat(predicates.or(Arrays.asList(predicates.none(), predicates.none())).apply(javaFile)).isFalse();
-
- // array
- assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.all()}).apply(javaFile)).isTrue();
- assertThat(predicates.or(new FilePredicate[] {predicates.all(), predicates.none()}).apply(javaFile)).isTrue();
- assertThat(predicates.or(new FilePredicate[] {predicates.none(), predicates.none()}).apply(javaFile)).isFalse();
- }
-
- @Test
- public void hasFilename() {
- assertThat(predicates.hasFilename("Action.java").apply(javaFile)).isTrue();
- }
-
- @Test
- public void hasExtension() {
- assertThat(predicates.hasExtension("java").apply(javaFile)).isTrue();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.io.IOException;
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.scanner.fs.predicates.FileExtensionPredicate.getExtension;
-
-public class FileExtensionPredicateTest {
-
- @Test
- public void should_match_correct_extension() throws IOException {
- FileExtensionPredicate predicate = new FileExtensionPredicate("bat");
- assertThat(predicate.apply(mockWithName("prog.bat"))).isTrue();
- assertThat(predicate.apply(mockWithName("prog.bat.bat"))).isTrue();
- }
-
- @Test
- public void should_not_match_incorrect_extension() throws IOException {
- FileExtensionPredicate predicate = new FileExtensionPredicate("bat");
- assertThat(predicate.apply(mockWithName("prog.batt"))).isFalse();
- assertThat(predicate.apply(mockWithName("prog.abat"))).isFalse();
- assertThat(predicate.apply(mockWithName("prog."))).isFalse();
- assertThat(predicate.apply(mockWithName("prog.bat."))).isFalse();
- assertThat(predicate.apply(mockWithName("prog.bat.batt"))).isFalse();
- assertThat(predicate.apply(mockWithName("prog"))).isFalse();
- }
-
- @Test
- public void should_match_correct_extension_case_insensitively() throws IOException {
- FileExtensionPredicate predicate = new FileExtensionPredicate("jAVa");
- assertThat(predicate.apply(mockWithName("Program.java"))).isTrue();
- assertThat(predicate.apply(mockWithName("Program.JAVA"))).isTrue();
- assertThat(predicate.apply(mockWithName("Program.Java"))).isTrue();
- assertThat(predicate.apply(mockWithName("Program.JaVa"))).isTrue();
- }
-
- @Test
- public void test_empty_extension() {
- assertThat(getExtension("prog")).isEmpty();
- assertThat(getExtension("prog.")).isEmpty();
- assertThat(getExtension(".")).isEmpty();
- }
-
- private InputFile mockWithName(String filename) throws IOException {
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.filename()).thenReturn(filename);
- return inputFile;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import java.io.IOException;
-import java.util.Collections;
-import org.junit.Test;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class FilenamePredicateTest {
- @Test
- public void should_match_file_by_filename() throws IOException {
- String filename = "some name";
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.filename()).thenReturn(filename);
-
- assertThat(new FilenamePredicate(filename).apply(inputFile)).isTrue();
- }
-
- @Test
- public void should_not_match_file_by_different_filename() throws IOException {
- String filename = "some name";
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.filename()).thenReturn(filename + "x");
-
- assertThat(new FilenamePredicate(filename).apply(inputFile)).isFalse();
- }
-
- @Test
- public void should_find_matching_file_in_index() throws IOException {
- String filename = "some name";
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.filename()).thenReturn(filename);
-
- FileSystem.Index index = mock(FileSystem.Index.class);
- when(index.getFilesByName(filename)).thenReturn(Collections.singleton(inputFile));
-
- assertThat(new FilenamePredicate(filename).get(index)).containsOnly(inputFile);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.junit.Test;
-import org.sonar.api.batch.fs.FilePredicate;
-
-import java.util.Arrays;
-import org.sonar.api.batch.fs.internal.PathPattern;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class OrPredicateTest {
-
- @Test
- public void flattenNestedOr() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- PathPatternPredicate pathPatternPredicate3 = new PathPatternPredicate(PathPattern.create("foo3/**"));
- FilePredicate orPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
- OrPredicate.create(Arrays.asList(pathPatternPredicate2, pathPatternPredicate3))));
- assertThat(((OrPredicate) orPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2, pathPatternPredicate3);
- }
-
- @Test
- public void simplifyOrExpressionsWhenEmpty() {
- FilePredicate orPredicate = OrPredicate.create(Arrays.asList());
- assertThat(orPredicate).isEqualTo(TruePredicate.TRUE);
- }
-
- @Test
- public void simplifyOrExpressionsWhenFalse() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- FilePredicate andPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
- FalsePredicate.FALSE, pathPatternPredicate2));
- assertThat(((OrPredicate) andPredicate).predicates()).containsExactly(pathPatternPredicate1, pathPatternPredicate2);
- }
-
- @Test
- public void simplifyAndExpressionsWhenTrue() {
- PathPatternPredicate pathPatternPredicate1 = new PathPatternPredicate(PathPattern.create("foo1/**"));
- PathPatternPredicate pathPatternPredicate2 = new PathPatternPredicate(PathPattern.create("foo2/**"));
- FilePredicate andPredicate = OrPredicate.create(Arrays.asList(pathPatternPredicate1,
- TruePredicate.TRUE, pathPatternPredicate2));
- assertThat(andPredicate).isEqualTo(TruePredicate.TRUE);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.fs.predicates;
-
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class RelativePathPredicateTest {
- @Test
- public void returns_false_when_path_is_invalid() {
- RelativePathPredicate predicate = new RelativePathPredicate("..");
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.relativePath()).thenReturn("path");
- assertThat(predicate.apply(inputFile)).isFalse();
- }
-
- @Test
- public void returns_true_if_matches() {
- RelativePathPredicate predicate = new RelativePathPredicate("path");
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.relativePath()).thenReturn("path");
- assertThat(predicate.apply(inputFile)).isTrue();
- }
-
- @Test
- public void returns_false_if_doesnt_match() {
- RelativePathPredicate predicate = new RelativePathPredicate("path1");
- InputFile inputFile = mock(InputFile.class);
- when(inputFile.relativePath()).thenReturn("path2");
- assertThat(predicate.apply(inputFile)).isFalse();
- }
-}
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.test.MutableTestPlan;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import org.sonar.scanner.config.DefaultConfiguration;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.scan.ProjectConfiguration;
-import org.sonar.scanner.sensor.SensorContextTester;
+import org.sonar.api.impl.sensor.SensorContextTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.protocol.Constants.Severity;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
import org.sonar.scanner.protocol.output.ScannerReport.TextRange;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.rule.NewActiveRule;
+import org.sonar.api.impl.rule.RulesBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.issue.DefaultIssue;
+import org.sonar.api.impl.issue.DefaultIssueLocation;
+import org.sonar.api.impl.sensor.DefaultExternalIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
-import org.sonar.scanner.rule.NewActiveRule;
-import org.sonar.scanner.rule.RulesBuilder;
-import org.sonar.scanner.sensor.DefaultExternalIssue;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.api.utils.WildcardPattern;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.issue.DefaultFilterableIssue;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.core.config.IssueExclusionProperties;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.core.config.IssueExclusionProperties;
import static org.assertj.core.api.Assertions.assertThat;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssuePattern;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.FileMetadata;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.FileMetadata;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;
import org.sonar.api.SonarProduct;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
+import org.sonar.api.batch.rule.LoadedActiveRule;
+import org.sonar.api.impl.server.RuleDefinitionContext;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.rule.RuleKey;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
import org.sonar.scanner.rule.ActiveRulesLoader;
-import org.sonar.scanner.rule.LoadedActiveRule;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scan.branch.ProjectBranches;
import org.sonar.scanner.scan.branch.ProjectPullRequests;
-import org.sonar.server.rule.RuleDefinitionContext;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import org.sonarqube.ws.Rules.ListResponse.Rule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.FileMetadata;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.FileMetadata;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.SonarEdition;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.fs.DefaultInputFile;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.scanner.rule.LoadedActiveRule;
+import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.rule.XooRulesDefinition;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
-import org.sonar.scanner.rule.LoadedActiveRule;
+import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.rule.HasTagSensor;
import org.sonar.xoo.rule.OneExternalIssuePerLineSensor;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.scan.ModuleConfiguration;
import org.sonar.scanner.scan.filesystem.ModuleCoverageAndDuplicationExclusions;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.impl.fs.SensorStrategy;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.sensor.ModuleSensorExtensionDictionnary;
import org.sonar.scanner.sensor.ModuleSensorWrapper;
import org.sonar.scanner.sensor.ModuleSensorsExecutor;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.scan.ProjectConfiguration;
import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
import org.sonar.api.CoreProperties;
import org.sonar.api.SonarQubeSide;
import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.utils.Version;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
Settings settings = new MapSettings();
settings.setProperty(CoreProperties.SERVER_ID, "123");
settings.setProperty(CoreProperties.SERVER_STARTTIME, "2010-05-18T17:59:00+0000");
- ScannerWsClient client = mock(ScannerWsClient.class);
+ DefaultScannerWsClient client = mock(DefaultScannerWsClient.class);
when(client.baseUrl()).thenReturn("http://foo.com");
DefaultServer metadata = new DefaultServer(((MapSettings) settings).asConfig(), client,
@Test
public void publicRootUrl() {
Settings settings = new MapSettings();
- ScannerWsClient client = mock(ScannerWsClient.class);
+ DefaultScannerWsClient client = mock(DefaultScannerWsClient.class);
when(client.baseUrl()).thenReturn("http://foo.com/");
DefaultServer metadata = new DefaultServer(((MapSettings) settings).asConfig(), client, null);
public void invalid_startup_date_throws_exception() {
Settings settings = new MapSettings();
settings.setProperty(CoreProperties.SERVER_STARTTIME, "invalid");
- ScannerWsClient client = mock(ScannerWsClient.class);
+ DefaultScannerWsClient client = mock(DefaultScannerWsClient.class);
DefaultServer metadata = new DefaultServer(((MapSettings) settings).asConfig(), client, null);
metadata.getStartedAt();
}
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.AnalysisMode;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.sensor.DefaultPostJobDescriptor;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.scanner.rule.DefaultActiveRules;
-import org.sonar.scanner.rule.NewActiveRule;
+import org.sonar.api.impl.rule.DefaultActiveRules;
+import org.sonar.api.batch.rule.NewActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.Constants;
import org.sonar.core.platform.PluginInfo;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.ProjectServerSettings;
" - sonar.projectKey=foo");
}
- @Test
- public void shouldNotDumpSQPropsInSystemProps() throws Exception {
- logTester.setLevel(LoggerLevel.DEBUG);
- ScannerReportWriter writer = new ScannerReportWriter(temp.newFolder());
- Properties props = new Properties();
- props.setProperty(COM_FOO, "bar");
- props.setProperty(SONAR_SKIP, "true");
- when(system2.properties()).thenReturn(props);
- DefaultInputModule rootModule = new DefaultInputModule(ProjectDefinition.create()
- .setBaseDir(temp.newFolder())
- .setWorkDir(temp.newFolder())
- .setProperty("sonar.projectKey", "foo")
- .setProperty(COM_FOO, "bar")
- .setProperty(SONAR_SKIP, "true"));
- when(store.allModules()).thenReturn(singletonList(rootModule));
- when(hierarchy.root()).thenReturn(rootModule);
-
- publisher.init(writer);
-
- List<String> lines = FileUtils.readLines(writer.getFileStructure().analysisLog(), StandardCharsets.UTF_8);
- assertThat(lines).containsExactly("Environment variables:",
- "System properties:",
- " - com.foo=bar",
- "SonarQube plugins:",
- "Global server settings:",
- "Project server settings:",
- "Project scanner properties:",
- " - sonar.projectKey=foo",
- " - sonar.skip=true");
- }
-
- @Test
- public void shouldNotDumpEnvTwice() throws Exception {
- logTester.setLevel(LoggerLevel.DEBUG);
- ScannerReportWriter writer = new ScannerReportWriter(temp.newFolder());
-
- Map<String, String> env = new HashMap<>();
- env.put(FOO, "BAR");
- env.put(BIZ, "BAZ");
- when(system2.envVariables()).thenReturn(env);
- DefaultInputModule rootModule = new DefaultInputModule(ProjectDefinition.create()
- .setBaseDir(temp.newFolder())
- .setWorkDir(temp.newFolder())
- .setProperty("sonar.projectKey", "foo")
- .setProperty("env." + FOO, "BAR"));
- when(store.allModules()).thenReturn(singletonList(rootModule));
- when(hierarchy.root()).thenReturn(rootModule);
- publisher.init(writer);
-
- String content = FileUtils.readFileToString(writer.getFileStructure().analysisLog(), StandardCharsets.UTF_8);
- assertThat(content).containsOnlyOnce(FOO);
- assertThat(content).containsOnlyOnce(BIZ);
- assertThat(content).containsSubsequence(BIZ, FOO);
-
- content = FileUtils.readFileToString(writer.getFileStructure().analysisLog(), StandardCharsets.UTF_8);
- assertThat(content).containsOnlyOnce(FOO);
- assertThat(content).containsOnlyOnce(BIZ);
- assertThat(content).doesNotContain("env." + FOO);
- }
-
@Test
public void shouldNotDumpSensitiveModuleProperties() throws Exception {
ScannerReportWriter writer = new ScannerReportWriter(temp.newFolder());
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.scm.ScmProvider;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.utils.DateUtils;
import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component;
import org.sonar.scanner.bootstrap.ScannerPlugin;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
GlobalAnalysisMode mode = mock(GlobalAnalysisMode.class);
ScanProperties properties = mock(ScanProperties.class);
- ScannerWsClient wsClient = mock(ScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
+ DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class, Mockito.RETURNS_DEEP_STUBS);
Server server = mock(Server.class);
InputModuleHierarchy moduleHierarchy = mock(InputModuleHierarchy.class);
DefaultInputModule root;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.scanner.WsTestUtil;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
public class DefaultMetricsRepositoryLoaderTest {
private static final String WS_URL = "/api/metrics/search?f=name,description,direction,qualitative,custom&ps=500&p=";
- private ScannerWsClient wsClient;
+ private DefaultScannerWsClient wsClient;
private DefaultMetricsRepositoryLoader metricsRepositoryLoader;
@Rule
@Before
public void setUp() throws IOException {
- wsClient = mock(ScannerWsClient.class);
+ wsClient = mock(DefaultScannerWsClient.class);
WsTestUtil.mockReader(wsClient, WS_URL + "1", new StringReader(IOUtils.toString(this.getClass().getResourceAsStream("DefaultMetricsRepositoryLoaderTest/page1.json"))));
WsTestUtil.mockReader(wsClient, WS_URL + "2", new StringReader(IOUtils.toString(this.getClass().getResourceAsStream("DefaultMetricsRepositoryLoaderTest/page2.json"))));
metricsRepositoryLoader = new DefaultMetricsRepositoryLoader(wsClient);
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.WsTestUtil;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
-import org.sonar.scanner.fs.DefaultInputFile;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.api.impl.fs.DefaultInputFile;
import org.sonarqube.ws.Batch.WsProjectResponse;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsRequest;
public ExpectedException thrown = ExpectedException.none();
private DefaultProjectRepositoriesLoader loader;
- private ScannerWsClient wsClient;
+ private DefaultScannerWsClient wsClient;
@Before
public void prepare() throws IOException {
- wsClient = mock(ScannerWsClient.class);
+ wsClient = mock(DefaultScannerWsClient.class);
InputStream is = mockData();
WsTestUtil.mockStream(wsClient, "/batch/project.protobuf?key=foo%3F", is);
loader = new DefaultProjectRepositoriesLoader(wsClient);
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.WsTestUtil;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.scan.ScanProperties;
import org.sonarqube.ws.Qualityprofiles;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
@Rule
public ExpectedException exception = ExpectedException.none();
- private ScannerWsClient wsClient = mock(ScannerWsClient.class);
+ private DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
private ScanProperties properties = mock(ScanProperties.class);
private DefaultQualityProfileLoader underTest = new DefaultQualityProfileLoader(properties, wsClient);
import java.util.Map;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonarqube.ws.Settings;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsResponse;
public class DefaultGlobalSettingsLoaderTest {
- private ScannerWsClient wsClient = mock(ScannerWsClient.class);
+ private DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
private DefaultGlobalSettingsLoader underTest = new DefaultGlobalSettingsLoader(wsClient);
@Test
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonarqube.ws.Settings;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsResponse;
public class DefaultProjectSettingsLoaderTest {
- private ScannerWsClient wsClient = mock(org.sonar.scanner.bootstrap.ScannerWsClient.class);
+ private DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
private ProcessedScannerProperties properties = mock(ProcessedScannerProperties.class);
private DefaultProjectSettingsLoader underTest = new DefaultProjectSettingsLoader(wsClient, properties);
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
+import org.sonar.api.batch.rule.NewActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.DateUtils;
import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile;
import java.util.stream.IntStream;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.scanner.WsTestUtil;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonarqube.ws.Rules;
import org.sonarqube.ws.Rules.Active;
private static final String SEVERITY_VALUE = Severity.MINOR;
private DefaultActiveRulesLoader loader;
- private ScannerWsClient wsClient;
+ private DefaultScannerWsClient wsClient;
@Before
public void setUp() {
- wsClient = mock(ScannerWsClient.class);
+ wsClient = mock(DefaultScannerWsClient.class);
BranchConfiguration branchConfig = mock(BranchConfiguration.class);
when(branchConfig.isShortOrPullRequest()).thenReturn(false);
loader = new DefaultActiveRulesLoader(wsClient);
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.scanner.WsTestUtil;
-import org.sonar.scanner.bootstrap.ScannerWsClient;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
import org.sonarqube.ws.Rules.ListResponse.Rule;
import static org.assertj.core.api.Assertions.assertThat;
@Test
public void testParseServerResponse() throws IOException {
- ScannerWsClient wsClient = mock(ScannerWsClient.class);
+ DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
InputStream is = Resources.asByteSource(this.getClass().getResource("DefaultRulesLoaderTest/response.protobuf")).openBufferedStream();
WsTestUtil.mockStream(wsClient, is);
DefaultRulesLoader loader = new DefaultRulesLoader(wsClient);
@Test
public void testError() throws IOException {
- ScannerWsClient wsClient = mock(ScannerWsClient.class);
+ DefaultScannerWsClient wsClient = mock(DefaultScannerWsClient.class);
InputStream is = ByteSource.wrap(new String("trash").getBytes()).openBufferedStream();
WsTestUtil.mockStream(wsClient, is);
DefaultRulesLoader loader = new DefaultRulesLoader(wsClient);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import org.sonar.api.rule.RuleKey;
-import org.junit.Test;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultRulesTest {
- @Test
- public void testRepeatedInternalKey() {
- List<NewRule> newRules = new LinkedList<>();
- newRules.add(createRule("key1", "repo", "internal"));
- newRules.add(createRule("key2", "repo", "internal"));
-
- DefaultRules rules = new DefaultRules(newRules);
- assertThat(rules.findByInternalKey("repo", "internal")).hasSize(2);
- assertThat(rules.find(RuleKey.of("repo", "key1"))).isNotNull();
- assertThat(rules.find(RuleKey.of("repo", "key2"))).isNotNull();
- assertThat(rules.findByRepository("repo")).hasSize(2);
- }
-
- @Test
- public void testNonExistingKey() {
- List<NewRule> newRules = new LinkedList<>();
- newRules.add(createRule("key1", "repo", "internal"));
- newRules.add(createRule("key2", "repo", "internal"));
-
- DefaultRules rules = new DefaultRules(newRules);
- assertThat(rules.findByInternalKey("xx", "xx")).hasSize(0);
- assertThat(rules.find(RuleKey.of("xxx", "xx"))).isNull();
- assertThat(rules.findByRepository("xxxx")).hasSize(0);
- }
-
- @Test
- public void testRepeatedRule() {
- List<NewRule> newRules = new LinkedList<>();
- newRules.add(createRule("key", "repo", "internal"));
- newRules.add(createRule("key", "repo", "internal"));
-
- DefaultRules rules = new DefaultRules(newRules);
- assertThat(rules.find(RuleKey.of("repo", "key"))).isNotNull();
- }
-
- private NewRule createRule(String key, String repo, String internalKey) {
- RuleKey ruleKey = RuleKey.of(repo, key);
- NewRule newRule = new NewRule(ruleKey);
- newRule.setInternalKey(internalKey);
-
- return newRule;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import com.google.common.collect.ImmutableMap;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class NewActiveRuleTest {
-
- private NewActiveRule.Builder builder;
-
- @Before
- public void setBuilder() {
- builder = new NewActiveRule.Builder();
- }
-
- @Test
- public void builder_should_set_every_param() {
- NewActiveRule rule = builder
- .setRuleKey(RuleKey.of("foo", "bar"))
- .setName("name")
- .setSeverity(Severity.CRITICAL)
- .setParam("key", "value")
- .setCreatedAt(1_000L)
- .setUpdatedAt(1_000L)
- .setInternalKey("internal_key")
- .setLanguage("language")
- .setTemplateRuleKey("templateRuleKey")
- .setQProfileKey("qProfileKey")
- .build();
-
- assertThat(rule.ruleKey).isEqualTo(RuleKey.of("foo", "bar"));
- assertThat(rule.name).isEqualTo("name");
- assertThat(rule.severity).isEqualTo(Severity.CRITICAL);
- assertThat(rule.params).isEqualTo(ImmutableMap.of("key", "value"));
- assertThat(rule.createdAt).isEqualTo(1_000L);
- assertThat(rule.updatedAt).isEqualTo(1_000L);
- assertThat(rule.internalKey).isEqualTo("internal_key");
- assertThat(rule.language).isEqualTo("language");
- assertThat(rule.templateRuleKey).isEqualTo("templateRuleKey");
- assertThat(rule.qProfileKey).isEqualTo("qProfileKey");
- }
-
- @Test
- public void severity_should_have_default_value() {
- NewActiveRule rule = builder.build();
- assertThat(rule.severity).isEqualTo(Severity.defaultSeverity());
- }
-
- @Test
- public void params_should_be_empty_map_if_no_params() {
- NewActiveRule rule = builder.build();
- assertThat(rule.params).isEqualTo(ImmutableMap.of());
- }
-
- @Test
- public void set_param_remove_param_if_value_is_null() {
- NewActiveRule rule = builder
- .setParam("foo", "bar")
- .setParam("removed", "value")
- .setParam("removed", null)
- .build();
- assertThat(rule.params).isEqualTo(ImmutableMap.of("foo", "bar"));
- }
-}
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.rule;
-
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.rule.Rule;
-import org.sonar.api.batch.rule.Rules;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class RulesBuilderTest {
- @org.junit.Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void no_rules() {
- RulesBuilder builder = new RulesBuilder();
- Rules rules = builder.build();
- assertThat(rules.findAll()).isEmpty();
- }
-
- @Test
- public void build_rules() {
- RulesBuilder builder = new RulesBuilder();
- NewRule newSquid1 = builder.add(RuleKey.of("squid", "S0001"));
- newSquid1.setName("Detect bug");
- newSquid1.setDescription("Detect potential bug");
- newSquid1.setInternalKey("foo=bar");
- newSquid1.setSeverity(Severity.CRITICAL);
- newSquid1.setStatus(RuleStatus.BETA);
- newSquid1.addParam("min");
- newSquid1.addParam("max").setDescription("Maximum");
- // most simple rule
- builder.add(RuleKey.of("squid", "S0002"));
- builder.add(RuleKey.of("findbugs", "NPE"));
-
- Rules rules = builder.build();
-
- assertThat(rules.findAll()).hasSize(3);
- assertThat(rules.findByRepository("squid")).hasSize(2);
- assertThat(rules.findByRepository("findbugs")).hasSize(1);
- assertThat(rules.findByRepository("unknown")).isEmpty();
-
- Rule squid1 = rules.find(RuleKey.of("squid", "S0001"));
- assertThat(squid1.key().repository()).isEqualTo("squid");
- assertThat(squid1.key().rule()).isEqualTo("S0001");
- assertThat(squid1.name()).isEqualTo("Detect bug");
- assertThat(squid1.description()).isEqualTo("Detect potential bug");
- assertThat(squid1.internalKey()).isEqualTo("foo=bar");
- assertThat(squid1.status()).isEqualTo(RuleStatus.BETA);
- assertThat(squid1.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(squid1.params()).hasSize(2);
- assertThat(squid1.param("min").key()).isEqualTo("min");
- assertThat(squid1.param("min").description()).isNull();
- assertThat(squid1.param("max").key()).isEqualTo("max");
- assertThat(squid1.param("max").description()).isEqualTo("Maximum");
-
- Rule squid2 = rules.find(RuleKey.of("squid", "S0002"));
- assertThat(squid2.key().repository()).isEqualTo("squid");
- assertThat(squid2.key().rule()).isEqualTo("S0002");
- assertThat(squid2.description()).isNull();
- assertThat(squid2.internalKey()).isNull();
- assertThat(squid2.status()).isEqualTo(RuleStatus.defaultStatus());
- assertThat(squid2.severity()).isEqualTo(Severity.defaultSeverity());
- assertThat(squid2.params()).isEmpty();
- }
-
- @Test
- public void fail_to_add_twice_the_same_rule() {
- RulesBuilder builder = new RulesBuilder();
- builder.add(RuleKey.of("squid", "S0001"));
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Rule 'squid:S0001' already exists");
-
- builder.add(RuleKey.of("squid", "S0001"));
- }
-
- @Test
- public void fail_to_add_twice_the_same_param() {
- RulesBuilder builder = new RulesBuilder();
- NewRule newRule = builder.add(RuleKey.of("squid", "S0001"));
- newRule.addParam("min");
- newRule.addParam("max");
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Parameter 'min' already exists on rule 'squid:S0001'");
-
- newRule.addParam("min");
- }
-}
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import org.junit.Test;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.scanner.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.batch.fs.InputFile.Status;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputPath;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.utils.MessageException;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.PathUtils;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.FileMetadata;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.FileMetadata;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputModule;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.SensorStrategy;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.IndexedFile;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.DefaultIndexedFile;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.fs.DefaultIndexedFile;
+import org.sonar.api.impl.config.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
import org.sonar.scanner.repository.SingleProjectRepository;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
import org.sonar.api.batch.scm.BlameLine;
public class DefaultBlameOutputTest {
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.scm.ScmProvider;
-import org.sonar.scanner.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.DefaultInputProject;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.branch.BranchConfiguration;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.batch.sensor.rule.NewAdHocRule;
-import org.sonar.api.rules.RuleType;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class DefaultAdHocRuleTest {
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- @Test
- public void store() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId("ruleId")
- .name("name")
- .description("desc")
- .severity(Severity.BLOCKER)
- .type(RuleType.CODE_SMELL);
- rule.save();
-
- assertThat(rule.engineId()).isEqualTo("engine");
- assertThat(rule.ruleId()).isEqualTo("ruleId");
- assertThat(rule.name()).isEqualTo("name");
- assertThat(rule.description()).isEqualTo("desc");
- assertThat(rule.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(rule.type()).isEqualTo(RuleType.CODE_SMELL);
-
- verify(storage).store(any(DefaultAdHocRule.class));
- }
-
-
- @Test
- public void description_is_optional() {
- SensorStorage storage = mock(SensorStorage.class);
- new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId("ruleId")
- .name("name")
- .severity(Severity.BLOCKER)
- .type(RuleType.CODE_SMELL)
- .save();
-
- verify(storage).store(any(DefaultAdHocRule.class));
- }
-
- @Test
- public void fail_to_store_if_no_engine_id() {
- SensorStorage storage = mock(SensorStorage.class);
- NewAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId(" ")
- .ruleId("ruleId")
- .name("name")
- .description("desc")
- .severity(Severity.BLOCKER)
- .type(RuleType.CODE_SMELL);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Engine id is mandatory");
- rule.save();
- }
-
- @Test
- public void fail_to_store_if_no_rule_id() {
- SensorStorage storage = mock(SensorStorage.class);
- NewAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId(" ")
- .name("name")
- .description("desc")
- .severity(Severity.BLOCKER)
- .type(RuleType.CODE_SMELL);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Rule id is mandatory");
- rule.save();
- }
-
- @Test
- public void fail_to_store_if_no_name() {
- SensorStorage storage = mock(SensorStorage.class);
- NewAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId("ruleId")
- .name(" ")
- .description("desc")
- .severity(Severity.BLOCKER)
- .type(RuleType.CODE_SMELL);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Name is mandatory");
- rule.save();
- }
-
-
- @Test
- public void fail_to_store_if_no_severity() {
- SensorStorage storage = mock(SensorStorage.class);
- NewAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId("ruleId")
- .name("name")
- .description("desc")
- .type(RuleType.CODE_SMELL);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Severity is mandatory");
- rule.save();
- }
-
- @Test
- public void fail_to_store_if_no_type() {
- SensorStorage storage = mock(SensorStorage.class);
- NewAdHocRule rule = new DefaultAdHocRule(storage)
- .engineId("engine")
- .ruleId("ruleId")
- .name("name")
- .description("desc")
- .severity(Severity.BLOCKER);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Type is mandatory");
- rule.save();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextPointer;
-import org.sonar.api.batch.sensor.error.NewAnalysisError;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-public class DefaultAnalysisErrorTest {
- private InputFile inputFile;
- private SensorStorage storage;
- private TextPointer textPointer;
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- @Before
- public void setUp() {
- inputFile = new TestInputFileBuilder("module1", "src/File.java").build();
- textPointer = new DefaultTextPointer(5, 2);
- storage = mock(SensorStorage.class);
- }
-
- @Test
- public void test_analysis_error() {
- DefaultAnalysisError analysisError = new DefaultAnalysisError(storage);
- analysisError.onFile(inputFile)
- .at(textPointer)
- .message("msg");
-
- assertThat(analysisError.location()).isEqualTo(textPointer);
- assertThat(analysisError.message()).isEqualTo("msg");
- assertThat(analysisError.inputFile()).isEqualTo(inputFile);
- }
-
- @Test
- public void test_save() {
- DefaultAnalysisError analysisError = new DefaultAnalysisError(storage);
- analysisError.onFile(inputFile).save();
-
- verify(storage).store(analysisError);
- verifyNoMoreInteractions(storage);
- }
-
- @Test
- public void test_no_storage() {
- exception.expect(NullPointerException.class);
- DefaultAnalysisError analysisError = new DefaultAnalysisError();
- analysisError.onFile(inputFile).save();
- }
-
- @Test
- public void test_validation() {
- try {
- new DefaultAnalysisError(storage).onFile(null);
- fail("Expected exception");
- } catch (IllegalArgumentException e) {
- // expected
- }
-
- NewAnalysisError error = new DefaultAnalysisError(storage).onFile(inputFile);
- try {
- error.onFile(inputFile);
- fail("Expected exception");
- } catch (IllegalStateException e) {
- // expected
- }
-
- error = new DefaultAnalysisError(storage).at(textPointer);
- try {
- error.at(textPointer);
- fail("Expected exception");
- } catch (IllegalStateException e) {
- // expected
- }
-
- try {
- new DefaultAnalysisError(storage).save();
- fail("Expected exception");
- } catch (NullPointerException e) {
- // expected
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-
-public class DefaultCpdTokensTest {
- private final SensorStorage sensorStorage = mock(SensorStorage.class);
-
- private final DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
- .setLines(2)
- .setOriginalLineStartOffsets(new int[] {0, 50})
- .setOriginalLineEndOffsets(new int[] {49, 100})
- .setLastValidOffset(101)
- .build();
-
- @Test
- public void save_no_tokens() {
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(inputFile);
-
- tokens.save();
-
- verify(sensorStorage).store(tokens);
-
- assertThat(tokens.inputFile()).isEqualTo(inputFile);
- }
-
- @Test
- public void save_one_token() {
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(inputFile)
- .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
-
- tokens.save();
-
- verify(sensorStorage).store(tokens);
-
- assertThat(tokens.getTokenLines()).extracting("value", "startLine", "hashCode", "startUnit", "endUnit").containsExactly(tuple("foo", 1, "foo".hashCode(), 1, 1));
- }
-
- @Test
- public void handle_exclusions() {
- inputFile.setExcludedForDuplication(true);
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(inputFile)
- .addToken(inputFile.newRange(1, 2, 1, 5), "foo");
-
- tokens.save();
-
- verifyZeroInteractions(sensorStorage);
-
- assertThat(tokens.getTokenLines()).isEmpty();
- }
-
- @Test
- public void dont_save_for_test_files() {
- DefaultInputFile testInputFile = new TestInputFileBuilder("foo", "src/Foo.java")
- .setLines(2)
- .setOriginalLineStartOffsets(new int[] {0, 50})
- .setOriginalLineEndOffsets(new int[] {49, 100})
- .setLastValidOffset(101)
- .setType(InputFile.Type.TEST)
- .build();
-
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(testInputFile)
- .addToken(testInputFile.newRange(1, 2, 1, 5), "foo");
-
- tokens.save();
- verifyZeroInteractions(sensorStorage);
- assertThat(tokens.getTokenLines()).isEmpty();
- }
-
- @Test
- public void save_many_tokens() {
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(inputFile)
- .addToken(inputFile.newRange(1, 2, 1, 5), "foo")
- .addToken(inputFile.newRange(1, 6, 1, 10), "bar")
- .addToken(inputFile.newRange(1, 20, 1, 25), "biz")
- .addToken(inputFile.newRange(2, 1, 2, 10), "next");
-
- tokens.save();
-
- verify(sensorStorage).store(tokens);
-
- assertThat(tokens.getTokenLines())
- .extracting("value", "startLine", "hashCode", "startUnit", "endUnit")
- .containsExactly(
- tuple("foobarbiz", 1, "foobarbiz".hashCode(), 1, 3),
- tuple("next", 2, "next".hashCode(), 4, 4));
- }
-
- @Test
- public void basic_validation() {
- SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage);
- try {
- tokens.save();
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).hasMessage("Call onFile() first");
- }
- try {
- tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).hasMessage("Call onFile() first");
- }
- try {
- tokens.addToken(null, "foo");
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).hasMessage("Range should not be null");
- }
- try {
- tokens.addToken(inputFile.newRange(1, 2, 1, 5), null);
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).hasMessage("Image should not be null");
- }
- }
-
- @Test
- public void validate_tokens_order() {
- SensorStorage sensorStorage = mock(SensorStorage.class);
- DefaultCpdTokens tokens = new DefaultCpdTokens(sensorStorage)
- .onFile(inputFile)
- .addToken(inputFile.newRange(1, 6, 1, 10), "bar");
-
- try {
- tokens.addToken(inputFile.newRange(1, 2, 1, 5), "foo");
- fail("Expected exception");
- } catch (Exception e) {
- assertThat(e).hasMessage("Tokens of file src/Foo.java should be provided in order.\n" +
- "Previous token: Range[from [line=1, lineOffset=6] to [line=1, lineOffset=10]]\n" +
- "Last token: Range[from [line=1, lineOffset=2] to [line=1, lineOffset=5]]");
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.IOException;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputComponent;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.RuleType;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.issue.DefaultIssueLocation;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class DefaultExternalIssueTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private DefaultInputProject project;
-
- @Before
- public void setup() throws IOException {
- project = new DefaultInputProject(ProjectDefinition.create()
- .setKey("foo")
- .setBaseDir(temp.newFolder())
- .setWorkDir(temp.newFolder()));
- }
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
- .initMetadata("Foo\nBar\n")
- .build();
-
- @Test
- public void build_file_issue() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(1))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .remediationEffortMinutes(10l)
- .type(RuleType.BUG)
- .severity(Severity.BLOCKER);
-
- assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_repo", "rule"));
- assertThat(issue.engineId()).isEqualTo("repo");
- assertThat(issue.ruleId()).isEqualTo("rule");
- assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
- assertThat(issue.remediationEffort()).isEqualTo(10l);
- assertThat(issue.type()).isEqualTo(RuleType.BUG);
- assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
- assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
-
- issue.save();
-
- verify(storage).store(issue);
- }
-
- @Test
- public void fail_to_store_if_no_type() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(1))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .remediationEffortMinutes(10l)
- .severity(Severity.BLOCKER);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Type is mandatory");
- issue.save();
- }
-
- @Test
- public void fail_to_store_if_primary_location_is_not_a_file() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(mock(InputComponent.class))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .remediationEffortMinutes(10l)
- .severity(Severity.BLOCKER);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("External issues must be located in files");
- issue.save();
- }
-
- @Test
- public void fail_to_store_if_primary_location_has_no_message() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(1)))
- .forRule(RuleKey.of("repo", "rule"))
- .remediationEffortMinutes(10l)
- .type(RuleType.BUG)
- .severity(Severity.BLOCKER);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("External issues must have a message");
- issue.save();
- }
-
- @Test
- public void fail_to_store_if_no_severity() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultExternalIssue issue = new DefaultExternalIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(1))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .remediationEffortMinutes(10l)
- .type(RuleType.BUG);
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Severity is mandatory");
- issue.save();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.Collection;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.DefaultTextRange;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.sonar.api.batch.sensor.highlighting.TypeOfText.COMMENT;
-import static org.sonar.api.batch.sensor.highlighting.TypeOfText.CPP_DOC;
-import static org.sonar.api.batch.sensor.highlighting.TypeOfText.KEYWORD;
-
-public class DefaultHighlightingTest {
-
- private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java")
- .setLines(2)
- .setOriginalLineStartOffsets(new int[] {0, 50})
- .setOriginalLineEndOffsets(new int[] {49, 100})
- .setLastValidOffset(101)
- .build();
-
- private Collection<SyntaxHighlightingRule> highlightingRules;
-
- @Rule
- public ExpectedException throwable = ExpectedException.none();
-
- @Before
- public void setUpSampleRules() {
-
- DefaultHighlighting highlightingDataBuilder = new DefaultHighlighting(mock(SensorStorage.class))
- .onFile(INPUT_FILE)
- .highlight(0, 10, COMMENT)
- .highlight(1, 10, 1, 12, KEYWORD)
- .highlight(24, 38, KEYWORD)
- .highlight(42, 50, KEYWORD)
- .highlight(24, 65, CPP_DOC)
- .highlight(12, 20, COMMENT);
-
- highlightingDataBuilder.save();
-
- highlightingRules = highlightingDataBuilder.getSyntaxHighlightingRuleSet();
- }
-
- @Test
- public void should_register_highlighting_rule() {
- assertThat(highlightingRules).hasSize(6);
- }
-
- private static TextRange rangeOf(int startLine, int startOffset, int endLine, int endOffset) {
- return new DefaultTextRange(new DefaultTextPointer(startLine, startOffset), new DefaultTextPointer(endLine, endOffset));
- }
-
- @Test
- public void should_order_by_start_then_end_offset() {
- assertThat(highlightingRules).extracting("range", TextRange.class).containsExactly(
- rangeOf(1, 0, 1, 10),
- rangeOf(1, 10, 1, 12),
- rangeOf(1, 12, 1, 20),
- rangeOf(1, 24, 2, 15),
- rangeOf(1, 24, 1, 38),
- rangeOf(1, 42, 2, 0));
- assertThat(highlightingRules).extracting("textType").containsExactly(COMMENT, KEYWORD, COMMENT, CPP_DOC, KEYWORD, KEYWORD);
- }
-
- @Test
- public void should_support_overlapping() {
- new DefaultHighlighting(mock(SensorStorage.class))
- .onFile(INPUT_FILE)
- .highlight(0, 15, KEYWORD)
- .highlight(8, 12, CPP_DOC)
- .save();
- }
-
- @Test
- public void should_prevent_start_equal_end() {
- throwable.expect(IllegalArgumentException.class);
- throwable
- .expectMessage("Unable to highlight file");
-
- new DefaultHighlighting(mock(SensorStorage.class))
- .onFile(INPUT_FILE)
- .highlight(10, 10, KEYWORD)
- .save();
- }
-
- @Test
- public void should_prevent_boudaries_overlapping() {
- throwable.expect(IllegalStateException.class);
- throwable
- .expectMessage("Cannot register highlighting rule for characters at Range[from [line=1, lineOffset=8] to [line=1, lineOffset=15]] as it overlaps at least one existing rule");
-
- new DefaultHighlighting(mock(SensorStorage.class))
- .onFile(INPUT_FILE)
- .highlight(0, 10, KEYWORD)
- .highlight(8, 15, KEYWORD)
- .save();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.apache.commons.lang.StringUtils;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.issue.DefaultIssueLocation;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.rules.ExpectedException.none;
-
-public class DefaultIssueLocationTest {
-
- @Rule
- public ExpectedException thrown = none();
-
- private InputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
- .initMetadata("Foo\nBar\n")
- .build();
-
- @Test
- public void should_build() {
- assertThat(new DefaultIssueLocation()
- .on(inputFile)
- .message("pipo bimbo")
- .message()
- ).isEqualTo("pipo bimbo");
- }
-
- @Test
- public void not_allowed_to_call_on_twice() {
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("on() already called");
- new DefaultIssueLocation()
- .on(inputFile)
- .on(inputFile)
- .message("Wrong way!");
- }
-
- @Test
- public void prevent_too_long_messages() {
- assertThat(new DefaultIssueLocation()
- .on(inputFile)
- .message(StringUtils.repeat("a", 4000)).message()).hasSize(4000);
-
- assertThat(new DefaultIssueLocation()
- .on(inputFile)
- .message(StringUtils.repeat("a", 4001)).message()).hasSize(4000);
- }
-
- @Test
- public void prevent_null_character_in_message_text() {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Character \\u0000 is not supported in issue message");
-
- new DefaultIssueLocation()
- .message("pipo " + '\u0000' + " bimbo");
- }
-
- @Test
- public void prevent_null_character_in_message_text_when_builder_has_been_initialized() {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage(customMatcher("Character \\u0000 is not supported in issue message", ", on component: src/Foo.php"));
-
- new DefaultIssueLocation()
- .on(inputFile)
- .message("pipo " + '\u0000' + " bimbo");
- }
-
- private Matcher<String> customMatcher(String startWith, String endWith) {
- return new TypeSafeMatcher<String>() {
- @Override
- public void describeTo(Description description) {
- description.appendText("Invalid message");
- }
-
- @Override
- protected boolean matchesSafely(final String item) {
- return item.startsWith(startWith) && item.endsWith(endWith);
- }
- };
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.File;
-import java.io.IOException;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.scanner.fs.DefaultInputDir;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.issue.DefaultIssue;
-import org.sonar.scanner.issue.DefaultIssueLocation;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class DefaultIssueTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private DefaultInputProject project;
-
- private DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.php")
- .initMetadata("Foo\nBar\n")
- .build();
-
- @Before
- public void prepare() throws IOException {
- project = new DefaultInputProject(ProjectDefinition.create()
- .setKey("foo")
- .setBaseDir(temp.newFolder())
- .setWorkDir(temp.newFolder()));
- }
-
- @Test
- public void build_file_issue() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultIssue issue = new DefaultIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(1))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .gap(10.0);
-
- assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputFile);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.primaryLocation().textRange().start().line()).isEqualTo(1);
- assertThat(issue.gap()).isEqualTo(10.0);
- assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
-
- issue.save();
-
- verify(storage).store(issue);
- }
-
- @Test
- public void move_directory_issue_to_project_root() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultIssue issue = new DefaultIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(new DefaultInputDir("foo", "src/main").setModuleBaseDir(project.getBaseDir()))
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .overrideSeverity(Severity.BLOCKER);
-
- assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.primaryLocation().textRange()).isNull();
- assertThat(issue.primaryLocation().message()).isEqualTo("[src/main] Wrong way!");
- assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
-
- issue.save();
-
- verify(storage).store(issue);
- }
-
- @Test
- public void move_submodule_issue_to_project_root() {
- File subModuleDirectory = new File(project.getBaseDir().toString(), "bar");
- subModuleDirectory.mkdir();
-
- ProjectDefinition subModuleDefinition = ProjectDefinition.create()
- .setKey("foo/bar")
- .setBaseDir(subModuleDirectory)
- .setWorkDir(subModuleDirectory);
- project.definition().addSubProject(subModuleDefinition);
- DefaultInputModule subModule = new DefaultInputModule(subModuleDefinition);
-
- SensorStorage storage = mock(SensorStorage.class);
- DefaultIssue issue = new DefaultIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(subModule)
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .overrideSeverity(Severity.BLOCKER);
-
- assertThat(issue.primaryLocation().inputComponent()).isEqualTo(project);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.primaryLocation().textRange()).isNull();
- assertThat(issue.primaryLocation().message()).isEqualTo("[bar] Wrong way!");
- assertThat(issue.overriddenSeverity()).isEqualTo(Severity.BLOCKER);
-
- issue.save();
-
- verify(storage).store(issue);
- }
-
- @Test
- public void build_project_issue() throws IOException {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultInputModule inputModule = new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder()));
- DefaultIssue issue = new DefaultIssue(project, storage)
- .at(new DefaultIssueLocation()
- .on(inputModule)
- .message("Wrong way!"))
- .forRule(RuleKey.of("repo", "rule"))
- .gap(10.0);
-
- assertThat(issue.primaryLocation().inputComponent()).isEqualTo(inputModule);
- assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("repo", "rule"));
- assertThat(issue.primaryLocation().textRange()).isNull();
- assertThat(issue.gap()).isEqualTo(10.0);
- assertThat(issue.primaryLocation().message()).isEqualTo("Wrong way!");
-
- issue.save();
-
- verify(storage).store(issue);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.IOException;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.scanner.fs.AbstractProjectOrModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class DefaultMeasureTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Test
- public void build_file_measure() {
- SensorStorage storage = mock(SensorStorage.class);
- DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
- .forMetric(CoreMetrics.LINES)
- .on(new TestInputFileBuilder("foo", "src/Foo.php").build())
- .withValue(3);
-
- assertThat(newMeasure.inputComponent()).isEqualTo(new TestInputFileBuilder("foo", "src/Foo.php").build());
- assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
- assertThat(newMeasure.value()).isEqualTo(3);
-
- newMeasure.save();
-
- verify(storage).store(newMeasure);
- }
-
- @Test
- public void build_project_measure() throws IOException {
- SensorStorage storage = mock(SensorStorage.class);
- AbstractProjectOrModule module = new DefaultInputProject(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder()));
- DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
- .forMetric(CoreMetrics.LINES)
- .on(module)
- .withValue(3);
-
- assertThat(newMeasure.inputComponent()).isEqualTo(module);
- assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
- assertThat(newMeasure.value()).isEqualTo(3);
-
- newMeasure.save();
-
- verify(storage).store(newMeasure);
- }
-
- @Test
- public void not_allowed_to_call_on_twice() throws IOException {
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("on() already called");
- new DefaultMeasure<Integer>()
- .on(new DefaultInputProject(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())))
- .on(new TestInputFileBuilder("foo", "src/Foo.php").build())
- .withValue(3)
- .save();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.config.internal.MapSettings;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultSensorDescriptorTest {
-
- @Test
- public void describe() {
- DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
- descriptor
- .name("Foo")
- .onlyOnLanguage("java")
- .onlyOnFileType(InputFile.Type.MAIN)
- .requireProperty("sonar.foo.reportPath", "sonar.foo.reportPath2")
- .createIssuesForRuleRepository("squid-java");
-
- assertThat(descriptor.name()).isEqualTo("Foo");
- assertThat(descriptor.languages()).containsOnly("java");
- assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN);
- MapSettings settings = new MapSettings();
- settings.setProperty("sonar.foo.reportPath", "foo");
- assertThat(descriptor.configurationPredicate().test(settings.asConfig())).isFalse();
- settings.setProperty("sonar.foo.reportPath2", "foo");
- assertThat(descriptor.configurationPredicate().test(settings.asConfig())).isTrue();
- assertThat(descriptor.ruleRepositories()).containsOnly("squid-java");
- }
-
-}
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.batch.sensor.issue.ExternalIssue;
import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.impl.config.MapSettings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.core.metric.ScannerMetrics;
+import org.sonar.api.impl.fs.DefaultInputDir;
+import org.sonar.api.impl.fs.DefaultInputFile;
+import org.sonar.api.impl.fs.DefaultInputModule;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultExternalIssue;
+import org.sonar.api.impl.sensor.DefaultHighlighting;
+import org.sonar.api.impl.sensor.DefaultMeasure;
+import org.sonar.api.impl.sensor.DefaultSignificantCode;
+import org.sonar.api.impl.sensor.DefaultSymbolTable;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.DefaultInputDir;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.issue.DefaultIssue;
-import org.sonar.scanner.issue.DefaultIssueLocation;
+import org.sonar.api.impl.issue.DefaultIssue;
+import org.sonar.api.impl.issue.DefaultIssueLocation;
import org.sonar.scanner.issue.IssuePublisher;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-public class DefaultSignificantCodeTest {
- private SensorStorage sensorStorage = mock(SensorStorage.class);
- private DefaultSignificantCode underTest = new DefaultSignificantCode(sensorStorage);
- private InputFile inputFile = TestInputFileBuilder.create("module", "file1.xoo")
- .setContents("this is\na file\n with some code")
- .build();
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- @Test
- public void should_save_ranges() {
- underTest.onFile(inputFile)
- .addRange(inputFile.selectLine(1))
- .save();
- verify(sensorStorage).store(underTest);
- }
-
- @Test
- public void fail_if_save_without_file() {
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Call onFile() first");
- underTest.save();
- }
-
- @Test
- public void fail_if_add_range_to_same_line_twice() {
- underTest.onFile(inputFile);
- underTest.addRange(inputFile.selectLine(1));
-
- exception.expect(IllegalStateException.class);
- exception.expectMessage("Significant code was already reported for line '1'.");
- underTest.addRange(inputFile.selectLine(1));
- }
-
- @Test
- public void fail_if_range_includes_many_lines() {
- underTest.onFile(inputFile);
-
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage("Ranges of significant code must be located in a single line");
- underTest.addRange(inputFile.newRange(1, 1, 2, 1));
- }
-
- @Test
- public void fail_if_add_range_before_setting_file() {
- exception.expect(IllegalStateException.class);
- exception.expectMessage("addRange() should be called after on()");
- underTest.addRange(inputFile.selectLine(1));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.util.Map;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.TextRange;
-import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.sensor.DefaultSymbolTable;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class DefaultSymbolTableTest {
-
- private static final InputFile INPUT_FILE = new TestInputFileBuilder("foo", "src/Foo.java")
- .setLines(2)
- .setOriginalLineStartOffsets(new int[] {0, 50})
- .setOriginalLineEndOffsets(new int[] {49, 100})
- .setLastValidOffset(101)
- .build();
-
- private Map<TextRange, Set<TextRange>> referencesPerSymbol;
-
- @Rule
- public ExpectedException throwable = ExpectedException.none();
-
- @Before
- public void setUpSampleSymbols() {
-
- DefaultSymbolTable symbolTableBuilder = new DefaultSymbolTable(mock(SensorStorage.class))
- .onFile(INPUT_FILE);
- symbolTableBuilder
- .newSymbol(0, 10)
- .newReference(12, 15)
- .newReference(2, 10, 2, 15);
-
- symbolTableBuilder.newSymbol(1, 12, 1, 15).newReference(52, 55);
-
- symbolTableBuilder.save();
-
- referencesPerSymbol = symbolTableBuilder.getReferencesBySymbol();
- }
-
- @Test
- public void should_register_symbols() {
- assertThat(referencesPerSymbol).hasSize(2);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.data.MapEntry.entry;
-
-public class InMemorySensorStorageTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- InMemorySensorStorage underTest = new InMemorySensorStorage();
-
- @Test
- public void test_storeProperty() {
- assertThat(underTest.contextProperties).isEmpty();
-
- underTest.storeProperty("foo", "bar");
- assertThat(underTest.contextProperties).containsOnly(entry("foo", "bar"));
- }
-
- @Test
- public void storeProperty_throws_IAE_if_key_is_null() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Key of context property must not be null");
-
- underTest.storeProperty(null, "bar");
- }
-
- @Test
- public void storeProperty_throws_IAE_if_value_is_null() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Value of context property must not be null");
-
- underTest.storeProperty("foo", null);
- }
-}
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.sensor.internal.SensorStorage;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.DefaultInputProject;
+import org.sonar.api.impl.context.SonarRuntimeImpl;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.Version;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputProject;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.batch.rule.NewActiveRule;
+import org.sonar.api.impl.config.MapSettings;
+import org.sonar.api.impl.fs.DefaultFileSystem;
+import org.sonar.api.impl.fs.TestInputFileBuilder;
+import org.sonar.api.impl.sensor.DefaultSensorDescriptor;
import org.sonar.api.rule.RuleKey;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
-import org.sonar.scanner.rule.NewActiveRule;
+import org.sonar.api.impl.rule.ActiveRulesBuilder;
import static org.assertj.core.api.Assertions.assertThat;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.scanner.sensor;
-
-import java.io.File;
-import java.io.IOException;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.rule.ActiveRules;
-import org.sonar.api.batch.rule.Severity;
-import org.sonar.api.batch.sensor.error.AnalysisError;
-import org.sonar.api.batch.sensor.error.NewAnalysisError;
-import org.sonar.api.batch.sensor.highlighting.TypeOfText;
-import org.sonar.api.batch.sensor.issue.NewExternalIssue;
-import org.sonar.api.batch.sensor.issue.NewIssue;
-import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.RuleType;
-import org.sonar.scanner.fs.DefaultFileSystem;
-import org.sonar.scanner.fs.DefaultInputFile;
-import org.sonar.scanner.fs.DefaultInputModule;
-import org.sonar.scanner.fs.DefaultTextPointer;
-import org.sonar.scanner.fs.TestInputFileBuilder;
-import org.sonar.scanner.rule.ActiveRulesBuilder;
-import org.sonar.scanner.rule.NewActiveRule;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.assertj.core.data.MapEntry.entry;
-
-public class SensorContextTesterTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- private SensorContextTester tester;
- private File baseDir;
-
- @Before
- public void prepare() throws Exception {
- baseDir = temp.newFolder();
- tester = SensorContextTester.create(baseDir);
- }
-
- @Test
- public void testSettings() {
- Settings settings = new MapSettings();
- settings.setProperty("foo", "bar");
- tester.setSettings(settings);
- assertThat(tester.settings().getString("foo")).isEqualTo("bar");
- }
-
- @Test
- public void testActiveRules() {
- NewActiveRule activeRule = new NewActiveRule.Builder()
- .setRuleKey(RuleKey.of("foo", "bar"))
- .build();
- ActiveRules activeRules = new ActiveRulesBuilder().addRule(activeRule).build();
- tester.setActiveRules(activeRules);
- assertThat(tester.activeRules().findAll()).hasSize(1);
- }
-
- @Test
- public void testFs() throws Exception {
- DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder());
- tester.setFileSystem(fs);
- assertThat(tester.fileSystem().baseDir()).isNotEqualTo(baseDir);
- }
-
- @Test
- public void testIssues() {
- assertThat(tester.allIssues()).isEmpty();
- NewIssue newIssue = tester.newIssue();
- newIssue
- .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
- .forRule(RuleKey.of("repo", "rule"))
- .save();
- newIssue = tester.newIssue();
- newIssue
- .at(newIssue.newLocation().on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
- .forRule(RuleKey.of("repo", "rule"))
- .save();
- assertThat(tester.allIssues()).hasSize(2);
- }
-
- @Test
- public void testExternalIssues() {
- assertThat(tester.allExternalIssues()).isEmpty();
- NewExternalIssue newExternalIssue = tester.newExternalIssue();
- newExternalIssue
- .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
- .forRule(RuleKey.of("repo", "rule"))
- .type(RuleType.BUG)
- .severity(Severity.BLOCKER)
- .save();
- newExternalIssue = tester.newExternalIssue();
- newExternalIssue
- .at(newExternalIssue.newLocation().message("message").on(new TestInputFileBuilder("foo", "src/Foo.java").build()))
- .type(RuleType.BUG)
- .severity(Severity.BLOCKER)
- .forRule(RuleKey.of("repo", "rule"))
- .save();
- assertThat(tester.allExternalIssues()).hasSize(2);
- }
-
- @Test
- public void testAnalysisErrors() {
- assertThat(tester.allAnalysisErrors()).isEmpty();
- NewAnalysisError newAnalysisError = tester.newAnalysisError();
-
- InputFile file = new TestInputFileBuilder("foo", "src/Foo.java").build();
- newAnalysisError.onFile(file)
- .message("error")
- .at(new DefaultTextPointer(5, 2))
- .save();
-
- assertThat(tester.allAnalysisErrors()).hasSize(1);
- AnalysisError analysisError = tester.allAnalysisErrors().iterator().next();
-
- assertThat(analysisError.inputFile()).isEqualTo(file);
- assertThat(analysisError.message()).isEqualTo("error");
- assertThat(analysisError.location()).isEqualTo(new DefaultTextPointer(5, 2));
-
- }
-
- @Test
- public void testMeasures() throws IOException {
- assertThat(tester.measures("foo:src/Foo.java")).isEmpty();
- assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNull();
- tester.<Integer>newMeasure()
- .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
- .forMetric(CoreMetrics.NCLOC)
- .withValue(2)
- .save();
- assertThat(tester.measures("foo:src/Foo.java")).hasSize(1);
- assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
- tester.<Integer>newMeasure()
- .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
- .forMetric(CoreMetrics.LINES)
- .withValue(4)
- .save();
- assertThat(tester.measures("foo:src/Foo.java")).hasSize(2);
- assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
- assertThat(tester.measure("foo:src/Foo.java", "lines")).isNotNull();
- tester.<Integer>newMeasure()
- .on(new DefaultInputModule(ProjectDefinition.create().setKey("foo").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())))
- .forMetric(CoreMetrics.DIRECTORIES)
- .withValue(4)
- .save();
- assertThat(tester.measures("foo")).hasSize(1);
- assertThat(tester.measure("foo", "directories")).isNotNull();
- }
-
- @Test(expected = IllegalStateException.class)
- public void duplicateMeasures() {
- tester.<Integer>newMeasure()
- .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
- .forMetric(CoreMetrics.NCLOC)
- .withValue(2)
- .save();
- tester.<Integer>newMeasure()
- .on(new TestInputFileBuilder("foo", "src/Foo.java").build())
- .forMetric(CoreMetrics.NCLOC)
- .withValue(2)
- .save();
- }
-
- @Test
- public void testHighlighting() {
- assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).isEmpty();
- tester.newHighlighting()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
- .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
- .highlight(8, 10, TypeOfText.CONSTANT)
- .highlight(9, 10, TypeOfText.COMMENT)
- .save();
- assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).containsExactly(TypeOfText.ANNOTATION);
- assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 9)).containsExactly(TypeOfText.CONSTANT, TypeOfText.COMMENT);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void duplicateHighlighting() {
- tester.newHighlighting()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
- .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
- .save();
- tester.newHighlighting()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
- .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
- .save();
- }
-
- @Test
- public void testSymbolReferences() {
- assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
-
- NewSymbolTable symbolTable = tester.newSymbolTable()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
- symbolTable
- .newSymbol(1, 8, 1, 10);
-
- symbolTable
- .newSymbol(1, 1, 1, 5)
- .newReference(6, 9)
- .newReference(1, 10, 1, 13);
-
- symbolTable.save();
-
- assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
- assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 8)).isEmpty();
- assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 3)).extracting("start.line", "start.lineOffset", "end.line", "end.lineOffset").containsExactly(tuple(1, 6, 1, 9),
- tuple(1, 10, 1, 13));
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void duplicateSymbolReferences() {
- NewSymbolTable symbolTable = tester.newSymbolTable()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
- symbolTable
- .newSymbol(1, 8, 1, 10);
-
- symbolTable.save();
-
- symbolTable = tester.newSymbolTable()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build());
- symbolTable
- .newSymbol(1, 8, 1, 10);
-
- symbolTable.save();
- }
-
- @Test
- public void testCoverageAtLineZero() {
- assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
- assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
-
- exception.expect(IllegalStateException.class);
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
- .lineHits(0, 3);
- }
-
- @Test
- public void testCoverageAtLineOutOfRange() {
- assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
- assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
- exception.expect(IllegalStateException.class);
-
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar").build())
- .lineHits(4, 3);
- }
-
- @Test
- public void testLineHits() {
- assertThat(tester.lineHits("foo:src/Foo.java", 1)).isNull();
- assertThat(tester.lineHits("foo:src/Foo.java", 4)).isNull();
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
- .lineHits(1, 2)
- .lineHits(2, 3)
- .save();
- assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(2);
- assertThat(tester.lineHits("foo:src/Foo.java", 2)).isEqualTo(3);
- }
-
- public void multipleCoverage() {
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
- .lineHits(1, 2)
- .conditions(3, 4, 2)
- .save();
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java").initMetadata("annot dsf fds foo bar\nasdas").build())
- .lineHits(1, 2)
- .conditions(3, 4, 3)
- .save();
- assertThat(tester.lineHits("foo:src/Foo.java", 1)).isEqualTo(4);
- assertThat(tester.conditions("foo:src/Foo.java", 3)).isEqualTo(4);
- assertThat(tester.coveredConditions("foo:src/Foo.java", 3)).isEqualTo(3);
- }
-
- @Test
- public void testConditions() {
- assertThat(tester.conditions("foo:src/Foo.java", 1)).isNull();
- assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isNull();
- tester.newCoverage()
- .onFile(new TestInputFileBuilder("foo", "src/Foo.java")
- .initMetadata("annot dsf fds foo bar\nasd\nasdas\nasdfas")
- .build())
- .conditions(1, 4, 2)
- .save();
- assertThat(tester.conditions("foo:src/Foo.java", 1)).isEqualTo(4);
- assertThat(tester.coveredConditions("foo:src/Foo.java", 1)).isEqualTo(2);
- }
-
- @Test
- public void testCpdTokens() {
- assertThat(tester.cpdTokens("foo:src/Foo.java")).isNull();
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
- .initMetadata("public class Foo {\n\n}")
- .build();
- tester.newCpdTokens()
- .onFile(inputFile)
- .addToken(inputFile.newRange(0, 6), "public")
- .addToken(inputFile.newRange(7, 12), "class")
- .addToken(inputFile.newRange(13, 16), "$IDENTIFIER")
- .addToken(inputFile.newRange(17, 18), "{")
- .addToken(inputFile.newRange(3, 0, 3, 1), "}")
- .save();
- assertThat(tester.cpdTokens("foo:src/Foo.java")).extracting("value", "startLine", "startUnit", "endUnit")
- .containsExactly(
- tuple("publicclass$IDENTIFIER{", 1, 1, 4),
- tuple("}", 3, 5, 5));
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void duplicateCpdTokens() {
- DefaultInputFile inputFile = new TestInputFileBuilder("foo", "src/Foo.java")
- .initMetadata("public class Foo {\n\n}")
- .build();
- tester.newCpdTokens()
- .onFile(inputFile)
- .addToken(inputFile.newRange(0, 6), "public")
- .save();
-
- tester.newCpdTokens()
- .onFile(inputFile)
- .addToken(inputFile.newRange(0, 6), "public")
- .save();
- }
-
- @Test
- public void testCancellation() {
- assertThat(tester.isCancelled()).isFalse();
- tester.setCancelled(true);
- assertThat(tester.isCancelled()).isTrue();
- }
-
- @Test
- public void testContextProperties() {
- assertThat(tester.getContextProperties()).isEmpty();
-
- tester.addContextProperty("foo", "bar");
- assertThat(tester.getContextProperties()).containsOnly(entry("foo", "bar"));
- }
-}
package org.sonar.scanner.util;
import org.junit.Test;
+import org.sonar.api.impl.utils.ScannerUtils;
import static org.assertj.core.api.Assertions.assertThat;