diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-07-09 18:36:52 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-07-09 18:36:52 +0200 |
commit | 4d5d1f5be3d1ace0199d39a086165e1086600a26 (patch) | |
tree | f44cfe310ddf3cd277fce68fbec36e90fdb255c8 /sonar-batch/src/test/java/org/sonar/batch | |
parent | 6a7de91d1fb7b3197da780079607a2489064d67b (diff) | |
download | sonarqube-4d5d1f5be3d1ace0199d39a086165e1086600a26.tar.gz sonarqube-4d5d1f5be3d1ace0199d39a086165e1086600a26.zip |
SONAR-5388 Introduce the SQALE Rating metric in SonarQube Core
Diffstat (limited to 'sonar-batch/src/test/java/org/sonar/batch')
3 files changed, 404 insertions, 0 deletions
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingDecoratorTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingDecoratorTest.java new file mode 100644 index 00000000000..1fe1574bffe --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingDecoratorTest.java @@ -0,0 +1,189 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.batch.debt; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.api.CoreProperties; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.test.IsMeasure; + +import static com.google.common.collect.Lists.newArrayList; +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class SqaleRatingDecoratorTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + static final Long ONE_DAY_IN_MINUTES = 8L * 60; + + Settings settings; + Metric[] metrics = {CoreMetrics.NCLOC, CoreMetrics.ABSTRACTNESS, CoreMetrics.COMPLEXITY}; + + @Mock + DecoratorContext context; + + DefaultFileSystem fs; + + File file = File.create("src/main/java/Foo.java"); + + SqaleRatingDecorator decorator; + + @Before + public void setUp() throws Exception { + settings = new Settings(); + + fs = new DefaultFileSystem(); + fs.add(new DefaultInputFile(file.getPath()) + .setLanguage("java") + .setFile(temp.newFile("Foo.java"))); + + decorator = new SqaleRatingDecorator(new SqaleRatingSettings(settings), metrics, fs); + } + + @Test + public void generates_metrics() throws Exception { + SqaleRatingDecorator decorator = new SqaleRatingDecorator(); + assertThat(decorator.generatesMetrics()).hasSize(2); + } + + @Test + public void depends_on_metrics() { + SqaleRatingDecorator decorator = new SqaleRatingDecorator(); + assertThat(decorator.dependsOnMetrics()).containsOnly(CoreMetrics.TECHNICAL_DEBT, CoreMetrics.NCLOC, CoreMetrics.COMPLEXITY); + } + + @Test + public void execute_on_project() throws Exception { + SqaleRatingDecorator decorator = new SqaleRatingDecorator(); + assertThat(decorator.shouldExecuteOnProject(null)).isTrue(); + } + + @Test + public void not_execute_on_unit_test() throws Exception { + File resource = mock(File.class); + when(resource.getQualifier()).thenReturn(Qualifiers.UNIT_TEST_FILE); + DecoratorContext context = mock(DecoratorContext.class); + + SqaleRatingDecorator decorator = new SqaleRatingDecorator(); + decorator.decorate(resource, context); + + verify(context, never()).saveMeasure(any(Measure.class)); + } + + @Test + public void save_total_rating_c() { + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, 2 * ONE_DAY_IN_MINUTES); + settings.setProperty(CoreProperties.SIZE_METRIC, "ncloc"); + settings.setProperty(CoreProperties.RATING_GRID, "1, 10,20,50"); + + when(context.getResource()).thenReturn(file); + when(context.getMeasure(CoreMetrics.NCLOC)).thenReturn(new Measure(CoreMetrics.NCLOC, 10.0)); + when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure(CoreMetrics.TECHNICAL_DEBT, 300.0 * ONE_DAY_IN_MINUTES)); + + decorator.decorate(file, context); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.RATING, 3.0))); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.DEVELOPMENT_COST, "9600"))); + + verify(context).getMeasure(CoreMetrics.NCLOC); + } + + @Test + public void save_total_rating_a() { + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, 2 * ONE_DAY_IN_MINUTES); + settings.setProperty(CoreProperties.SIZE_METRIC, "ncloc"); + settings.setProperty(CoreProperties.RATING_GRID, "1, 10,20,50"); + + when(context.getResource()).thenReturn(file); + when(context.getMeasure(CoreMetrics.NCLOC)).thenReturn(new Measure(CoreMetrics.NCLOC, 10.0)); + when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure(CoreMetrics.TECHNICAL_DEBT, 0.0)); + + decorator.decorate(file, context); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.RATING, 1.0))); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.DEVELOPMENT_COST, "9600"))); + + verify(context).getMeasure(CoreMetrics.NCLOC); + } + + @Test + public void save_total_rating_e() { + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, 2 * ONE_DAY_IN_MINUTES); + settings.setProperty(CoreProperties.SIZE_METRIC, "ncloc"); + settings.setProperty(CoreProperties.RATING_GRID, "1, 10,20,50"); + + when(context.getResource()).thenReturn(file); + when(context.getMeasure(CoreMetrics.NCLOC)).thenReturn(new Measure(CoreMetrics.NCLOC, 10.0)); + when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure(CoreMetrics.TECHNICAL_DEBT, 100000000000.0)); + + decorator.decorate(file, context); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.RATING, 5.0))); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.DEVELOPMENT_COST, "9600"))); + + verify(context).getMeasure(CoreMetrics.NCLOC); + } + + @Test + public void save_total_rating_on_project() { + settings.setProperty(CoreProperties.RATING_GRID, "1, 10,20,50"); + + when(context.getResource()).thenReturn(new Project("Sample")); + when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure(CoreMetrics.TECHNICAL_DEBT, 300.0 * ONE_DAY_IN_MINUTES)); + when(context.getChildrenMeasures(CoreMetrics.DEVELOPMENT_COST)).thenReturn(newArrayList(new Measure(CoreMetrics.DEVELOPMENT_COST, Double.toString(20.0 * ONE_DAY_IN_MINUTES)))); + + decorator.decorate(mock(File.class), context); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.RATING, 3.0))); + verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.DEVELOPMENT_COST, "9600"))); + + verify(context, never()).getMeasure(CoreMetrics.NCLOC); + } + + @Test + public void translate_rating_to_letter() { + assertThat(SqaleRatingDecorator.toRatingLetter(null)).isNull(); + assertThat(SqaleRatingDecorator.toRatingLetter(1)).isEqualTo("A"); + assertThat(SqaleRatingDecorator.toRatingLetter(4)).isEqualTo("D"); + } + + @Test(expected = IllegalArgumentException.class) + public void test_rating_out_of_range() { + SqaleRatingDecorator.toRatingLetter(89); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingGridTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingGridTest.java new file mode 100644 index 00000000000..cabf747826a --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingGridTest.java @@ -0,0 +1,72 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.batch.debt; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.fest.assertions.Assertions.assertThat; + +public class SqaleRatingGridTest { + + private SqaleRatingGrid ratingGrid; + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Before + public void setUp() { + double[] gridValues = new double[] {0.1, 0.2, 0.5, 1}; + ratingGrid = new SqaleRatingGrid(gridValues); + } + + @Test + public void return_grade_lower_bound() throws Exception { + assertThat(ratingGrid.getGradeLowerBound(SqaleRatingGrid.SqaleRating.A)).isEqualTo(0); + assertThat(ratingGrid.getGradeLowerBound(SqaleRatingGrid.SqaleRating.B)).isEqualTo(0.1); + assertThat(ratingGrid.getGradeLowerBound(SqaleRatingGrid.SqaleRating.C)).isEqualTo(0.2); + assertThat(ratingGrid.getGradeLowerBound(SqaleRatingGrid.SqaleRating.D)).isEqualTo(0.5); + assertThat(ratingGrid.getGradeLowerBound(SqaleRatingGrid.SqaleRating.E)).isEqualTo(1); + } + + @Test + public void return_rating_matching_density() throws Exception { + assertThat(ratingGrid.getRatingForDensity(0)).isEqualTo(1); + assertThat(ratingGrid.getRatingForDensity(0.05)).isEqualTo(1); + assertThat(ratingGrid.getRatingForDensity(0.1)).isEqualTo(2); + assertThat(ratingGrid.getRatingForDensity(0.15)).isEqualTo(2); + assertThat(ratingGrid.getRatingForDensity(0.2)).isEqualTo(3); + assertThat(ratingGrid.getRatingForDensity(0.25)).isEqualTo(3); + assertThat(ratingGrid.getRatingForDensity(0.5)).isEqualTo(4); + assertThat(ratingGrid.getRatingForDensity(0.65)).isEqualTo(4); + assertThat(ratingGrid.getRatingForDensity(1)).isEqualTo(5); + assertThat(ratingGrid.getRatingForDensity(1.01)).isEqualTo(5); + } + + @Test + public void fail_on_invalid_density() throws Exception { + throwable.expect(RuntimeException.class); + + ratingGrid.getRatingForDensity(-1); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingSettingsTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingSettingsTest.java new file mode 100644 index 00000000000..cd784f135fc --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/debt/SqaleRatingSettingsTest.java @@ -0,0 +1,143 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.batch.debt; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; + +import static org.fest.assertions.Assertions.assertThat; + + +public class SqaleRatingSettingsTest { + + private static final Metric[] metrics = {CoreMetrics.NCLOC, CoreMetrics.ABSTRACTNESS, CoreMetrics.COMPLEXITY}; + + private Settings settings; + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Before + public void setUp() { + settings = new Settings(); + } + + @Test + public void load_rating_grid() throws Exception { + settings.setProperty(CoreProperties.RATING_GRID, "1,3.4,8,50"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + double[] grid = configurationLoader.getRatingGrid(); + assertThat(grid).hasSize(4); + assertThat(grid[0]).isEqualTo(1.0); + assertThat(grid[1]).isEqualTo(3.4); + assertThat(grid[2]).isEqualTo(8.0); + assertThat(grid[3]).isEqualTo(50.0); + } + + @Test + public void load_work_units_for_language() throws Exception { + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, "50"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + assertThat(configurationLoader.getWorkUnitsBySizePoint("defaultLanguage")).isEqualTo(50L); + } + + @Test + public void load_size_metric_for_language() throws Exception { + settings.setProperty(CoreProperties.SIZE_METRIC, "complexity"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + assertThat(configurationLoader.getSizeMetric("defaultLanguage", metrics)).isEqualTo(CoreMetrics.COMPLEXITY); + } + + @Test + public void load_overridden_values_for_language() throws Exception { + + String aLanguage = "aLanguage"; + String anotherLanguage = "anotherLanguage"; + + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS, "0,1"); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, aLanguage); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "30"); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.NCLOC_KEY); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, anotherLanguage); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "1" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_SIZE_METRIC_KEY, CoreMetrics.COMPLEXITY_KEY); + + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + assertThat(configurationLoader.getSizeMetric(aLanguage, metrics)).isEqualTo(CoreMetrics.NCLOC); + assertThat(configurationLoader.getSizeMetric(anotherLanguage, metrics)).isEqualTo(CoreMetrics.COMPLEXITY); + assertThat(configurationLoader.getWorkUnitsBySizePoint(aLanguage)).isEqualTo(30L); + assertThat(configurationLoader.getWorkUnitsBySizePoint(anotherLanguage)).isEqualTo(40L); + } + + @Test + public void fail_on_invalid_rating_grid_configuration() throws Exception { + + throwable.expect(IllegalArgumentException.class); + settings.setProperty(CoreProperties.RATING_GRID, "a b c"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + configurationLoader.getRatingGrid(); + } + + @Test + public void fail_on_invalid_work_unit_value() throws Exception { + throwable.expect(IllegalArgumentException.class); + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, "a"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + configurationLoader.getSizeMetric("aLanguage", metrics); + } + + @Test + public void fail_on_unknown_metric_key() throws Exception { + throwable.expect(IllegalArgumentException.class); + settings.setProperty(CoreProperties.SIZE_METRIC, "unknown"); + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + configurationLoader.getSizeMetric("aLanguage", metrics); + } + + @Test + public void use_generic_value_when_specific_setting_is_missing() throws Exception { + String aLanguage = "aLanguage"; + + settings.setProperty(CoreProperties.SIZE_METRIC, "complexity"); + settings.setProperty(CoreProperties.MAN_DAYS_BY_SIZE_POINT, "30"); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS, "0"); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_LANGUAGE_KEY, aLanguage); + settings.setProperty(CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS + "." + "0" + "." + CoreProperties.LANGUAGE_SPECIFIC_PARAMETERS_MAN_DAYS_KEY, "40"); + + SqaleRatingSettings configurationLoader = new SqaleRatingSettings(settings); + + assertThat(configurationLoader.getSizeMetric(aLanguage, metrics)).isEqualTo(CoreMetrics.COMPLEXITY); + assertThat(configurationLoader.getWorkUnitsBySizePoint(aLanguage)).isEqualTo(40L); + } +} |