diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2019-06-19 13:56:51 -0500 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-07-12 20:21:14 +0200 |
commit | 93dc9770902dc7e168869d88b5ad731bfc0bedd9 (patch) | |
tree | 97ba885661d5cd9a2115fe212df31bacec9f9947 /sonar-plugin-api-impl/src/test | |
parent | 7c7d9b6b90244d2c974207862071caccdb2c9bb5 (diff) | |
download | sonarqube-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')
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 Binary files differnew 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 |