From f478e8f0db76bca44e626e6eb9bdf0e002523fb0 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 10 Dec 2012 14:03:50 +0100 Subject: [PATCH] SONAR-3825 fix sorting on variations --- .../resources/org/sonar/l10n/core.properties | 2 +- .../core/measure/MeasureFilterExecutor.java | 2 +- .../core/measure/MeasureFilterFactory.java | 43 ++-- .../sonar/core/measure/MeasureFilterSort.java | 4 +- .../measure/MeasureFilterFactoryTest.java | 203 ++++++++++++++++++ 5 files changed, 238 insertions(+), 16 deletions(-) create mode 100644 sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index deb28d04312..aaf89c1c938 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -1542,7 +1542,7 @@ metric.accessors.description=Accessors metric.alert_status.name=Alert metric.alert_status.description=Alert -metric.alert_status.abbreviation=Alt +metric.alert_status.abbreviation=A metric.classes.name=Classes metric.classes.description=Classes diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java index da5004aef38..1c9d3774d10 100644 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java +++ b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterExecutor.java @@ -106,7 +106,7 @@ public class MeasureFilterExecutor implements ServerComponent { private static boolean validateSort(MeasureFilter filter) { boolean valid = true; - if (filter.sort().getPeriod() != null && filter.sort().getPeriod() < 1) { + if (filter.sort().period() != null && filter.sort().period() < 1) { valid = false; } if (filter.sort().onMeasures() && filter.sort().metric() == null) { diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java index 42a92d07fdd..50d01873196 100644 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java +++ b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterFactory.java @@ -56,6 +56,16 @@ public class MeasureFilterFactory implements ServerComponent { } filter.setResourceName((String) properties.get("nameSearch")); filter.setResourceKeyRegexp((String) properties.get("keyRegexp")); + if (properties.containsKey("onFavourites")) { + filter.setUserFavourites(Boolean.valueOf((String) properties.get("onFavourites"))); + } + fillDateConditions(filter, properties); + fillSorting(filter, properties); + fillMeasureConditions(properties, filter); + return filter; + } + + private void fillDateConditions(MeasureFilter filter, Map properties) { if (properties.containsKey("fromDate")) { filter.setFromDate(toDate((String) properties.get("fromDate"))); } else if (properties.containsKey("ageMaxDays")) { @@ -66,28 +76,37 @@ public class MeasureFilterFactory implements ServerComponent { } else if (properties.containsKey("ageMinDays")) { filter.setToDate(toDays((String) properties.get("ageMinDays"))); } + } - if (properties.containsKey("onFavourites")) { - filter.setUserFavourites(Boolean.valueOf((String) properties.get("onFavourites"))); - } - if (properties.containsKey("asc")) { - filter.setSortAsc(Boolean.valueOf((String) properties.get("asc"))); + private void fillMeasureConditions(Map properties, MeasureFilter filter) { + for (int index = 1; index <= 3; index++) { + MeasureFilterCondition condition = toCondition(properties, index); + if (condition != null) { + filter.addCondition(condition); + } } + } + + private void fillSorting(MeasureFilter filter, Map properties) { String s = (String) properties.get("sort"); if (s != null) { if (StringUtils.startsWith(s, "metric:")) { - filter.setSortOnMetric(metricFinder.findByKey(StringUtils.substringAfter(s, "metric:"))); + String[] fields = StringUtils.split(s, ':'); + Metric metric = metricFinder.findByKey(fields[1]); + if (metric != null) { + filter.setSortOnMetric(metric); + if (fields.length == 3) { + filter.setSortOnPeriod(Integer.parseInt(fields[2])); + } + } } else { filter.setSortOn(MeasureFilterSort.Field.valueOf(s.toUpperCase())); } } - for (int index = 1; index <= 3; index++) { - MeasureFilterCondition condition = toCondition(properties, index); - if (condition != null) { - filter.addCondition(condition); - } + + if (properties.containsKey("asc")) { + filter.setSortAsc(Boolean.valueOf((String) properties.get("asc"))); } - return filter; } private MeasureFilterCondition toCondition(Map props, int index) { diff --git a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java index b29e11b549f..3fc40ed04f1 100644 --- a/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java +++ b/sonar-core/src/main/java/org/sonar/core/measure/MeasureFilterSort.java @@ -43,7 +43,7 @@ class MeasureFilterSort { this.metric = metric; } - Integer getPeriod() { + Integer period() { return period; } @@ -77,7 +77,7 @@ class MeasureFilterSort { String column() { // only numeric metrics can be sorted by database, else results are sorted programmatically. - String column = null; + String column; switch (field) { case KEY: column = "p.kee"; diff --git a/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java new file mode 100644 index 00000000000..936b3afff77 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/measure/MeasureFilterFactoryTest.java @@ -0,0 +1,203 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.core.measure; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.MetricFinder; +import org.sonar.api.utils.DateUtils; + +import java.util.List; +import java.util.Map; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MeasureFilterFactoryTest { + @Test + public void sort_on_measure_value() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of("sort", "metric:ncloc"); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("pm.value"); + assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc"); + assertThat(filter.sort().period()).isNull(); + } + + @Test + public void sort_on_measure_variation() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of("sort", "metric:ncloc:3"); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("pm.variation_value_3"); + assertThat(filter.sort().metric().getKey()).isEqualTo("ncloc"); + assertThat(filter.sort().period()).isEqualTo(3); + } + + @Test + public void sort_on_name() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of("sort", "name"); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("p.long_name"); + assertThat(filter.sort().metric()).isNull(); + assertThat(filter.sort().period()).isNull(); + } + + @Test + public void fallback_on_name_sort_when_metric_is_unknown() { + MetricFinder finder = mock(MetricFinder.class); + when(finder.findByKey(anyString())).thenReturn(null); + MeasureFilterFactory factory = new MeasureFilterFactory(finder); + Map props = ImmutableMap.of("sort", "metric:sqale_index"); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("p.long_name"); + assertThat(filter.sort().metric()).isNull(); + assertThat(filter.sort().period()).isNull(); + assertThat(filter.sort().isAsc()).isTrue(); + } + + @Test + public void descending_sort() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of("asc", "false"); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("p.long_name"); + assertThat(filter.sort().metric()).isNull(); + assertThat(filter.sort().period()).isNull(); + assertThat(filter.sort().isAsc()).isFalse(); + } + + @Test + public void ascending_sort_by_default() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = Maps.newHashMap(); + MeasureFilter filter = factory.create(props); + + assertThat(filter.sort().column()).isEqualTo("p.long_name"); + assertThat(filter.sort().metric()).isNull(); + assertThat(filter.sort().period()).isNull(); + assertThat(filter.sort().isAsc()).isTrue(); + } + + @Test + public void date_conditions() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of( + "fromDate", "2012-01-25", + "toDate", "2012-02-18" + ); + MeasureFilter filter = factory.create(props); + + assertThat(DateUtils.formatDate(filter.getFromDate())).isEqualTo("2012-01-25"); + assertThat(DateUtils.formatDate(filter.getToDate())).isEqualTo("2012-02-18"); + } + + @Test + public void age_conditions() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of( + "ageMaxDays", "50", + "ageMinDays", "3" + ); + MeasureFilter filter = factory.create(props); + + long msFrom = System.currentTimeMillis() - filter.getFromDate().getTime(); + long msTo = System.currentTimeMillis() - filter.getToDate().getTime(); + assertThat(millisecondsToDays(msFrom)).isEqualTo(50); + assertThat(millisecondsToDays(msTo)).isEqualTo(3); + } + + @Test + public void measure_value_condition() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of( + "c1_metric", "complexity", + "c1_op", "gte", + "c1_val", "3.14" + ); + MeasureFilter filter = factory.create(props); + + List conditions = filter.getMeasureConditions(); + assertThat(conditions).hasSize(1); + assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity"); + assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS); + assertThat(conditions.get(0).value()).isEqualTo(3.14); + assertThat(conditions.get(0).period()).isNull(); + } + + @Test + public void measure_variation_condition() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of( + "c1_metric", "complexity", + "c1_op", "gte", + "c1_val", "3.14", + "c1_period", "3" + ); + MeasureFilter filter = factory.create(props); + + List conditions = filter.getMeasureConditions(); + assertThat(conditions).hasSize(1); + assertThat(conditions.get(0).metric().getKey()).isEqualTo("complexity"); + assertThat(conditions.get(0).operator()).isEqualTo(MeasureFilterCondition.Operator.GREATER_OR_EQUALS); + assertThat(conditions.get(0).value()).isEqualTo(3.14); + assertThat(conditions.get(0).period()).isEqualTo(3); + } + + @Test + public void ignore_partial_measure_condition() { + MeasureFilterFactory factory = new MeasureFilterFactory(newMetricFinder()); + Map props = ImmutableMap.of( + "c1_op", "gte", + "c1_val", "3.14" + ); + MeasureFilter filter = factory.create(props); + + List conditions = filter.getMeasureConditions(); + assertThat(conditions).isEmpty(); + } + + private int millisecondsToDays(long ms) { + return (int) (ms / (1000L * 60 * 60 * 24)); + } + + private MetricFinder newMetricFinder() { + MetricFinder finder = mock(MetricFinder.class); + when(finder.findByKey(anyString())).thenAnswer(new Answer() { + public Metric answer(InvocationOnMock invocationOnMock) throws Throwable { + String key = (String) invocationOnMock.getArguments()[0]; + return new Metric.Builder(key, key, Metric.ValueType.INT).create(); + } + }); + return finder; + } +} -- 2.39.5