aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api-impl/src/test
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2019-06-19 13:56:51 -0500
committerSonarTech <sonartech@sonarsource.com>2019-07-12 20:21:14 +0200
commit93dc9770902dc7e168869d88b5ad731bfc0bedd9 (patch)
tree97ba885661d5cd9a2115fe212df31bacec9f9947 /sonar-plugin-api-impl/src/test
parent7c7d9b6b90244d2c974207862071caccdb2c9bb5 (diff)
downloadsonarqube-93dc9770902dc7e168869d88b5ad731bfc0bedd9.tar.gz
sonarqube-93dc9770902dc7e168869d88b5ad731bfc0bedd9.zip
Extract implementation from plugin API and create new module sonar-plugin-api-impl
Diffstat (limited to 'sonar-plugin-api-impl/src/test')
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MapSettingsTest.java566
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MultivaluePropertyTest.java265
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/MetadataLoaderTest.java80
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/SonarRuntimeImplTest.java68
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultFileSystemTest.java140
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputDirTest.java64
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputFileTest.java313
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputModuleTest.java110
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputProjectTest.java86
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/FileMetadataTest.java307
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/MetadataTest.java39
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/PathPatternTest.java110
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/TestInputFileBuilderTest.java72
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/charhandler/IntArrayListTest.java55
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/AndPredicateTest.java116
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/DefaultFilePredicatesTest.java245
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FileExtensionPredicateTest.java72
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FilenamePredicateTest.java63
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/OrPredicateTest.java66
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/RelativePathPredicateTest.java53
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/DefaultRulesTest.java74
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/RulesBuilderTest.java114
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAdHocRuleTest.java156
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAnalysisErrorTest.java114
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultCpdTokensTest.java170
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultExternalIssueTest.java160
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultHighlightingTest.java126
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueLocationTest.java108
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueTest.java159
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultMeasureTest.java92
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSensorDescriptorTest.java51
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSignificantCodeTest.java82
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSymbolTableTest.java72
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/InMemorySensorStorageTest.java60
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/SensorContextTesterTest.java375
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/server/DefaultNewRuleTest.java98
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/AlwaysIncreasingSystem2Test.java118
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/DefaultTempFolderTest.java124
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/JUnitTempFolderTest.java53
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/ScannerUtilsTest.java52
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/WorkDurationTest.java200
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/ws/SimpleGetRequestTest.java110
-rw-r--r--sonar-plugin-api-impl/src/test/resources/org/sonar/api/impl/fs/glyphicons-halflings-regular.woffbin0 -> 16448 bytes
43 files changed, 5558 insertions, 0 deletions
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MapSettingsTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MapSettingsTest.java
new file mode 100644
index 00000000000..922d767dfac
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MapSettingsTest.java
@@ -0,0 +1,566 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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"});
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MultivaluePropertyTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MultivaluePropertyTest.java
new file mode 100644
index 00000000000..63e3c442cfd
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/config/MultivaluePropertyTest.java
@@ -0,0 +1,265 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/MetadataLoaderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/MetadataLoaderTest.java
new file mode 100644
index 00000000000..e6106a3dfe3
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/MetadataLoaderTest.java
@@ -0,0 +1,80 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/SonarRuntimeImplTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/SonarRuntimeImplTest.java
new file mode 100644
index 00000000000..617dbafeda2
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/context/SonarRuntimeImplTest.java
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultFileSystemTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultFileSystemTest.java
new file mode 100644
index 00000000000..552387c70e6
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultFileSystemTest.java
@@ -0,0 +1,140 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputDirTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputDirTest.java
new file mode 100644
index 00000000000..263032b33f2
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputDirTest.java
@@ -0,0 +1,64 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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");
+
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputFileTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputFileTest.java
new file mode 100644
index 00000000000..7e22203de37
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputFileTest.java
@@ -0,0 +1,313 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputModuleTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputModuleTest.java
new file mode 100644
index 00000000000..ac1a2c40417
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputModuleTest.java
@@ -0,0 +1,110 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputProjectTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputProjectTest.java
new file mode 100644
index 00000000000..bd3f4939af0
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/DefaultInputProjectTest.java
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/FileMetadataTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/FileMetadataTest.java
new file mode 100644
index 00000000000..0f3f1d5965e
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/FileMetadataTest.java
@@ -0,0 +1,307 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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'.");
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/MetadataTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/MetadataTest.java
new file mode 100644
index 00000000000..49ecf8984d6
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/MetadataTest.java
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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");
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/PathPatternTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/PathPatternTest.java
new file mode 100644
index 00000000000..c214469f081
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/PathPatternTest.java
@@ -0,0 +1,110 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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");
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/TestInputFileBuilderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/TestInputFileBuilderTest.java
new file mode 100644
index 00000000000..4fb37a2fd77
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/TestInputFileBuilderTest.java
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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());
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/charhandler/IntArrayListTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/charhandler/IntArrayListTest.java
new file mode 100644
index 00000000000..50c37d8a565
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/charhandler/IntArrayListTest.java
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/AndPredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/AndPredicateTest.java
new file mode 100644
index 00000000000..e02d5e433f4
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/AndPredicateTest.java
@@ -0,0 +1,116 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/DefaultFilePredicatesTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/DefaultFilePredicatesTest.java
new file mode 100644
index 00000000000..6d9cd4eafed
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/DefaultFilePredicatesTest.java
@@ -0,0 +1,245 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FileExtensionPredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FileExtensionPredicateTest.java
new file mode 100644
index 00000000000..0f60f6bc36d
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FileExtensionPredicateTest.java
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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;
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FilenamePredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FilenamePredicateTest.java
new file mode 100644
index 00000000000..052ff51c015
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/FilenamePredicateTest.java
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/OrPredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/OrPredicateTest.java
new file mode 100644
index 00000000000..489d6366543
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/OrPredicateTest.java
@@ -0,0 +1,66 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/RelativePathPredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/RelativePathPredicateTest.java
new file mode 100644
index 00000000000..e7e2efd9571
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/fs/predicates/RelativePathPredicateTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/DefaultRulesTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/DefaultRulesTest.java
new file mode 100644
index 00000000000..c55551687b9
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/DefaultRulesTest.java
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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;
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/RulesBuilderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/RulesBuilderTest.java
new file mode 100644
index 00000000000..1330f906502
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/rule/RulesBuilderTest.java
@@ -0,0 +1,114 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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");
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAdHocRuleTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAdHocRuleTest.java
new file mode 100644
index 00000000000..fd766c2739b
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAdHocRuleTest.java
@@ -0,0 +1,156 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAnalysisErrorTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAnalysisErrorTest.java
new file mode 100644
index 00000000000..9f6be9d2d9f
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultAnalysisErrorTest.java
@@ -0,0 +1,114 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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
+ }
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultCpdTokensTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultCpdTokensTest.java
new file mode 100644
index 00000000000..fd2c60de2d1
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultCpdTokensTest.java
@@ -0,0 +1,170 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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]]");
+ }
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultExternalIssueTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultExternalIssueTest.java
new file mode 100644
index 00000000000..06ff4064f88
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultExternalIssueTest.java
@@ -0,0 +1,160 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultHighlightingTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultHighlightingTest.java
new file mode 100644
index 00000000000..99beb98927d
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultHighlightingTest.java
@@ -0,0 +1,126 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueLocationTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueLocationTest.java
new file mode 100644
index 00000000000..540a0bbc0c9
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueLocationTest.java
@@ -0,0 +1,108 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+ };
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueTest.java
new file mode 100644
index 00000000000..f88a099f391
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultIssueTest.java
@@ -0,0 +1,159 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultMeasureTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultMeasureTest.java
new file mode 100644
index 00000000000..0c7ece260ce
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultMeasureTest.java
@@ -0,0 +1,92 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSensorDescriptorTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSensorDescriptorTest.java
new file mode 100644
index 00000000000..b09b5ed9eab
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSensorDescriptorTest.java
@@ -0,0 +1,51 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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");
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSignificantCodeTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSignificantCodeTest.java
new file mode 100644
index 00000000000..f6d7f45281e
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSignificantCodeTest.java
@@ -0,0 +1,82 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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));
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSymbolTableTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSymbolTableTest.java
new file mode 100644
index 00000000000..affd87bbef4
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/DefaultSymbolTableTest.java
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/InMemorySensorStorageTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/InMemorySensorStorageTest.java
new file mode 100644
index 00000000000..25b44f5cfbb
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/InMemorySensorStorageTest.java
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/SensorContextTesterTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/SensorContextTesterTest.java
new file mode 100644
index 00000000000..9684c7cdcb2
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/sensor/SensorContextTesterTest.java
@@ -0,0 +1,375 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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"));
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/server/DefaultNewRuleTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/server/DefaultNewRuleTest.java
new file mode 100644
index 00000000000..361785b49f7
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/server/DefaultNewRuleTest.java
@@ -0,0 +1,98 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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);
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/AlwaysIncreasingSystem2Test.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/AlwaysIncreasingSystem2Test.java
new file mode 100644
index 00000000000..30953e690d6
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/AlwaysIncreasingSystem2Test.java
@@ -0,0 +1,118 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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;
+ }
+ }
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/DefaultTempFolderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/DefaultTempFolderTest.java
new file mode 100644
index 00000000000..b21d2077ebb
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/DefaultTempFolderTest.java
@@ -0,0 +1,124 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/JUnitTempFolderTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/JUnitTempFolderTest.java
new file mode 100644
index 00000000000..5b765c344cc
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/JUnitTempFolderTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/ScannerUtilsTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/ScannerUtilsTest.java
new file mode 100644
index 00000000000..0390d1faf90
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/ScannerUtilsTest.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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";
+ }
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/WorkDurationTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/WorkDurationTest.java
new file mode 100644
index 00000000000..3c1e2f971ff
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/utils/WorkDurationTest.java
@@ -0,0 +1,200 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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();
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/ws/SimpleGetRequestTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/ws/SimpleGetRequestTest.java
new file mode 100644
index 00000000000..fb20cf22f30
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/impl/ws/SimpleGetRequestTest.java
@@ -0,0 +1,110 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with 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("");
+ }
+}
diff --git a/sonar-plugin-api-impl/src/test/resources/org/sonar/api/impl/fs/glyphicons-halflings-regular.woff b/sonar-plugin-api-impl/src/test/resources/org/sonar/api/impl/fs/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000000..2cc3e4852a5
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/resources/org/sonar/api/impl/fs/glyphicons-halflings-regular.woff
Binary files differ