From 1b5abf08fe1fe69de73a710f55de7251d5fbea36 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 20 Feb 2017 13:44:56 +0100 Subject: SONAR-8290 Improve filter to accept multiple values --- .../sonar/server/component/ws/FilterParser.java | 82 ++++++++++++---- .../component/ws/ProjectMeasuresQueryFactory.java | 26 +++-- .../server/measure/index/ProjectMeasuresQuery.java | 23 +---- .../server/component/ws/FilterParserTest.java | 75 +++++++++++--- .../ws/ProjectMeasuresQueryFactoryTest.java | 109 ++++++++------------- .../ws/ProjectMeasuresQueryValidatorTest.java | 8 +- .../measure/index/ProjectMeasuresIndexTest.java | 2 +- .../measure/index/ProjectMeasuresQueryTest.java | 19 +++- 8 files changed, 206 insertions(+), 138 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/FilterParser.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/FilterParser.java index 5b5b90be0c9..caa60c55b5a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/FilterParser.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/FilterParser.java @@ -20,6 +20,7 @@ package org.sonar.server.component.ws; import com.google.common.base.Splitter; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; @@ -29,11 +30,18 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.core.util.stream.Collectors; +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.String.format; +import static java.util.Arrays.stream; +import static java.util.Objects.requireNonNull; + public class FilterParser { private static final Splitter CRITERIA_SPLITTER = Splitter.on(Pattern.compile("and", Pattern.CASE_INSENSITIVE)); - private static final Pattern TERNARY_PATTERN = Pattern.compile("(\\w+)\\s+(\\S+)\\s+(\\w+)"); - private static final Pattern SINGLE_KEY_PATTERN = Pattern.compile("(\\w+)"); + private static final Splitter IN_VALUES_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults(); + + private static final Pattern PATTERN = Pattern.compile("(\\w+)\\s*([<>]?[=]?)\\s*(\\S*)", Pattern.CASE_INSENSITIVE); + private static final Pattern PATTERN_HAVING_VALUES = Pattern.compile("(\\w+)\\s+(in)\\s+\\((.*)\\)", Pattern.CASE_INSENSITIVE); public static List parse(String filter) { return StreamSupport.stream(CRITERIA_SPLITTER.split(filter.trim()).spliterator(), false) @@ -46,11 +54,11 @@ public class FilterParser { private static Criterion parseCriterion(String rawCriterion) { try { - Criterion criterion = tryParsingTernaryCriterion(rawCriterion); + Criterion criterion = tryParsingCriterionHavingValues(rawCriterion); if (criterion != null) { return criterion; } - criterion = tryParsingSingleKey(rawCriterion); + criterion = tryParsingCriterionNotHavingValues(rawCriterion); if (criterion != null) { return criterion; } @@ -61,41 +69,46 @@ public class FilterParser { } @CheckForNull - private static Criterion tryParsingTernaryCriterion(String criterion) { - Matcher matcher = TERNARY_PATTERN.matcher(criterion); + private static Criterion tryParsingCriterionNotHavingValues(String criterion) { + Matcher matcher = PATTERN.matcher(criterion); if (!matcher.find()) { return null; } Criterion.Builder builder = new Criterion.Builder(); builder.setKey(matcher.group(1)); String operatorValue = matcher.group(2); - builder.setOperator(operatorValue); - builder.setValue(matcher.group(3)); + String value = matcher.group(3); + if (!isNullOrEmpty(operatorValue) && !isNullOrEmpty(value)) { + builder.setOperator(Operator.getByValue(operatorValue)); + builder.setValue(value); + } return builder.build(); } @CheckForNull - private static Criterion tryParsingSingleKey(String criterion) { - Matcher matcher = SINGLE_KEY_PATTERN.matcher(criterion); + private static Criterion tryParsingCriterionHavingValues(String criterion) { + Matcher matcher = PATTERN_HAVING_VALUES.matcher(criterion); if (!matcher.find()) { return null; } - String key = matcher.group(1); - if (key.length() != criterion.length()) { - return null; - } - return new Criterion.Builder().setKey(key).build(); + Criterion.Builder builder = new Criterion.Builder(); + builder.setKey(matcher.group(1)); + builder.setOperator(Operator.IN); + builder.setValues(IN_VALUES_SPLITTER.splitToList(matcher.group(3))); + return builder.build(); } public static class Criterion { private final String key; - private final String operator; + private final Operator operator; private final String value; + private final List values; private Criterion(Builder builder) { this.key = builder.key; this.operator = builder.operator; this.value = builder.value; + this.values = builder.values; } public String getKey() { @@ -103,7 +116,7 @@ public class FilterParser { } @CheckForNull - public String getOperator() { + public Operator getOperator() { return operator; } @@ -112,21 +125,26 @@ public class FilterParser { return value; } + public List getValues() { + return values; + } + public static Builder builder() { return new Builder(); } public static class Builder { private String key; - private String operator; + private Operator operator; private String value; + private List values = new ArrayList<>(); public Builder setKey(String key) { this.key = key; return this; } - public Builder setOperator(@Nullable String operator) { + public Builder setOperator(@Nullable Operator operator) { this.operator = operator; return this; } @@ -136,10 +154,36 @@ public class FilterParser { return this; } + public Builder setValues(List values) { + this.values = requireNonNull(values, "Values cannot be null"); + return this; + } + public Criterion build() { return new Criterion(this); } } } + public enum Operator { + LT("<"), LTE("<="), GT(">"), GTE(">="), EQ("="), IN("in"); + + String value; + + Operator(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static Operator getByValue(String value) { + return stream(Operator.values()) + .filter(operator -> operator.getValue().equalsIgnoreCase(value)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value))); + } + } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java index 600262c150b..618204acaf6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java @@ -19,18 +19,22 @@ */ package org.sonar.server.component.ws; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; import org.sonar.api.measures.Metric.Level; +import org.sonar.server.component.ws.FilterParser.Operator; import org.sonar.server.measure.index.ProjectMeasuresQuery; import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; import static java.util.Locale.ENGLISH; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.server.component.ws.FilterParser.Operator.EQ; import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; class ProjectMeasuresQueryFactory { @@ -53,25 +57,33 @@ class ProjectMeasuresQueryFactory { return; } - String operatorValue = criterion.getOperator(); - checkArgument(operatorValue != null, "Operator cannot be null for '%s'", key); String value = criterion.getValue(); checkArgument(value != null, "Value cannot be null for '%s'", key); - Operator operator = Operator.getByValue(criterion.getOperator()); + Operator operator = criterion.getOperator(); + checkArgument(operator != null, "Operator cannot be null for '%s'", key); if (ALERT_STATUS_KEY.equals(key)) { - checkArgument(operator.equals(Operator.EQ), "Only equals operator is available for quality gate criteria"); - query.setQualityGateStatus(Level.valueOf(value)); + processQualityGateStatus(criterion, query); } else { query.addMetricCriterion(new MetricCriterion(key, operator, parseValue(value))); } } + private static void processQualityGateStatus(FilterParser.Criterion criterion, ProjectMeasuresQuery query) { + Operator operator = criterion.getOperator(); + String value = criterion.getValue(); + checkArgument(EQ.equals(operator), "Only equals operator is available for quality gate criteria"); + Arrays.stream(Level.values()).filter(level -> level.name().equalsIgnoreCase(value)).findFirst() + .orElseThrow(() -> new IllegalArgumentException(format("Unknown quality gate status : '%s'", value))); + query.setQualityGateStatus(Level.valueOf(value)); + } + private static double parseValue(String value) { try { return Double.parseDouble(value); } catch (NumberFormatException e) { - throw new IllegalArgumentException(String.format("Value '%s' is not a number", value)); + throw new IllegalArgumentException(format("Value '%s' is not a number", value)); } } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java index cf52b20fb3b..86af9f37ae2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresQuery.java @@ -27,9 +27,8 @@ import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.measures.Metric; -import static java.lang.String.format; -import static java.util.Arrays.stream; import static java.util.Objects.requireNonNull; +import static org.sonar.server.component.ws.FilterParser.Operator; public class ProjectMeasuresQuery { @@ -121,24 +120,4 @@ public class ProjectMeasuresQuery { } } - public enum Operator { - LT("<"), LTE("<="), GT(">"), GTE(">="), EQ("="); - - String value; - - Operator(String value) { - this.value = value; - } - - String getValue() { - return value; - } - - public static Operator getByValue(String value) { - return stream(Operator.values()) - .filter(operator -> operator.getValue().equals(value)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(format("Unknown operator '%s'", value))); - } - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/FilterParserTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/FilterParserTest.java index d751798d64b..a93644f57e8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/FilterParserTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/FilterParserTest.java @@ -25,8 +25,16 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.server.component.ws.FilterParser.Criterion; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; +import static org.sonar.server.component.ws.FilterParser.Operator.EQ; +import static org.sonar.server.component.ws.FilterParser.Operator.GT; +import static org.sonar.server.component.ws.FilterParser.Operator.GTE; +import static org.sonar.server.component.ws.FilterParser.Operator.IN; +import static org.sonar.server.component.ws.FilterParser.Operator.LT; +import static org.sonar.server.component.ws.FilterParser.Operator.LTE; public class FilterParserTest { @@ -40,8 +48,8 @@ public class FilterParserTest { assertThat(criterion) .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue) .containsOnly( - tuple("ncloc", ">", "10"), - tuple("coverage", "<=", "80")); + tuple("ncloc", GT, "10"), + tuple("coverage", LTE, "80")); } @Test @@ -51,7 +59,27 @@ public class FilterParserTest { assertThat(criterion) .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue) .containsOnly( - tuple("ncloc", ">", "10")); + tuple("ncloc", GT, "10")); + } + + @Test + public void parse_filter_having_in_operator() throws Exception { + List criterion = FilterParser.parse("ncloc in (80,90)"); + + assertThat(criterion) + .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValues, Criterion::getValue) + .containsOnly( + tuple("ncloc", IN, asList("80", "90"), null)); + } + + @Test + public void parse_filter_having_in_operator_ignores_white_spaces() throws Exception { + List criterion = FilterParser.parse(" ncloc in ( 80 , 90 ) "); + + assertThat(criterion) + .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValues, Criterion::getValue) + .containsOnly( + tuple("ncloc", IN, asList("80", "90"), null)); } @Test @@ -81,8 +109,8 @@ public class FilterParserTest { assertThat(criterion) .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue) .containsOnly( - tuple("ncloc", ">", "10"), - tuple("coverage", "<=", "80"), + tuple("ncloc", GT, "10"), + tuple("coverage", LTE, "80"), tuple("isFavorite", null, null)); } @@ -93,7 +121,34 @@ public class FilterParserTest { assertThat(criterion) .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue) .containsOnly( - tuple("alert_status", "=", "OK")); + tuple("alert_status", EQ, "OK")); + } + + @Test + public void parse_filter_without_any_space_in_criteria() throws Exception { + List criterion = FilterParser.parse("ncloc>10 and coverage<=80 and language in (java,js)"); + + assertThat(criterion) + .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue, Criterion::getValues) + .containsOnly( + tuple("ncloc", GT, "10", emptyList()), + tuple("coverage", LTE, "80", emptyList()), + tuple("language", IN, null, asList("java", "js"))); + } + + @Test + public void parse_filter_having_all_operators() throws Exception { + List criterion = FilterParser.parse("ncloc < 10 and coverage <= 80 and debt > 50 and duplication >= 56.5 and security_rating = 1 and language in (java,js)"); + + assertThat(criterion) + .extracting(Criterion::getKey, Criterion::getOperator, Criterion::getValue, Criterion::getValues) + .containsOnly( + tuple("ncloc", LT, "10", emptyList()), + tuple("coverage", LTE, "80", emptyList()), + tuple("debt", GT, "50", emptyList()), + tuple("duplication", GTE, "56.5", emptyList()), + tuple("security_rating", EQ, "1", emptyList()), + tuple("language", IN, null, asList("java", "js"))); } @Test @@ -110,12 +165,4 @@ public class FilterParserTest { assertThat(criterion).hasSize(4); } - @Test - public void fail_when_missing_value() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Cannot parse 'ncloc ='"); - - FilterParser.parse("ncloc = "); - } - } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java index 3a836a9b275..b7c326ba571 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactoryTest.java @@ -27,7 +27,6 @@ import org.junit.rules.ExpectedException; import org.sonar.server.component.ws.FilterParser.Criterion; import org.sonar.server.measure.index.ProjectMeasuresQuery; import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; import org.sonar.server.tester.UserSessionRule; import static java.util.Arrays.asList; @@ -36,6 +35,11 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; +import static org.sonar.server.component.ws.FilterParser.Operator; +import static org.sonar.server.component.ws.FilterParser.Operator.EQ; +import static org.sonar.server.component.ws.FilterParser.Operator.GT; +import static org.sonar.server.component.ws.FilterParser.Operator.IN; +import static org.sonar.server.component.ws.FilterParser.Operator.LTE; import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery; import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.OK; @@ -49,79 +53,72 @@ public class ProjectMeasuresQueryFactoryTest { @Test public void create_query() throws Exception { List criteria = asList( - Criterion.builder().setKey("ncloc").setOperator(">").setValue("10").build(), - Criterion.builder().setKey("coverage").setOperator("<=").setValue("80").build()); + Criterion.builder().setKey("ncloc").setOperator(GT).setValue("10").build(), + Criterion.builder().setKey("coverage").setOperator(LTE).setValue("80").build()); ProjectMeasuresQuery underTest = newProjectMeasuresQuery(criteria, emptySet()); assertThat(underTest.getMetricCriteria()) .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) .containsOnly( - tuple("ncloc", Operator.GT, 10d), + tuple("ncloc", GT, 10d), tuple("coverage", Operator.LTE, 80d)); } @Test - public void create_query_having_lesser_than_operation() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator("<").setValue("10").build()), - emptySet()); + public void fail_when_not_double() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Value 'ten' is not a number"); - assertThat(query.getMetricCriteria()) - .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) - .containsOnly(tuple("ncloc", Operator.LT, 10d)); + newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue("ten").build()), + emptySet()); } @Test - public void create_query_having_lesser_than_or_equals_operation() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator("<=").setValue("10").build()), - emptySet()); + public void fail_when_no_operator() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Operator cannot be null for 'ncloc'"); - assertThat(query.getMetricCriteria()) - .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) - .containsOnly(tuple("ncloc", Operator.LTE, 10d)); + newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(null).setValue("ten").build()), + emptySet()); } @Test - public void create_query_having_greater_than_operation() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue("10").build()), - emptySet()); + public void fail_when_no_value() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Value cannot be null for 'ncloc'"); - assertThat(query.getMetricCriteria()) - .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) - .containsOnly(tuple("ncloc", Operator.GT, 10d)); + newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue(null).build()), + emptySet()); } @Test - public void create_query_having_greater_than_or_equals_operation() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">=").setValue("10").build()), + public void create_query_on_quality_gate() throws Exception { + ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("alert_status").setOperator(EQ).setValue("OK").build()), emptySet()); - assertThat(query.getMetricCriteria()) - .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) - .containsOnly(tuple("ncloc", Operator.GTE, 10d)); + assertThat(query.getQualityGateStatus().get().name()).isEqualTo(OK.name()); } @Test - public void create_query_having_equal_operation() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator("=").setValue("10").build()), - emptySet()); + public void fail_to_create_query_on_quality_gate_when_operator_is_not_equal() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Only equals operator is available for quality gate criteria"); - assertThat(query.getMetricCriteria()) - .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) - .containsOnly(tuple("ncloc", Operator.EQ, 10d)); + newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("alert_status").setOperator(GT).setValue("OK").build()), emptySet()); } @Test - public void create_query_on_quality_gate() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("alert_status").setOperator("=").setValue("OK").build()), - emptySet()); + public void fail_to_create_query_on_quality_gate_when_value_is_incorrect() throws Exception { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Unknown quality gate status : 'unknown'"); - assertThat(query.getQualityGateStatus().get().name()).isEqualTo(OK.name()); + newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("alert_status").setOperator(EQ).setValue("unknown").build()), emptySet()); } @Test public void do_not_filter_on_projectUuids_if_criteria_non_empty_and_projectUuid_is_null() { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator("=").setValue("10").build()), + ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(EQ).setValue("10").build()), null); assertThat(query.getProjectUuids()).isEmpty(); @@ -129,7 +126,7 @@ public class ProjectMeasuresQueryFactoryTest { @Test public void filter_on_projectUuids_if_projectUuid_is_empty_and_criteria_non_empty() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue("10").build()), + ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(GT).setValue("10").build()), emptySet()); assertThat(query.getProjectUuids()).isPresent(); @@ -137,7 +134,7 @@ public class ProjectMeasuresQueryFactoryTest { @Test public void filter_on_projectUuids_if_projectUuid_is_non_empty_and_criteria_non_empty() throws Exception { - ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue("10").build()), + ProjectMeasuresQuery query = newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(GT).setValue("10").build()), Collections.singleton("foo")); assertThat(query.getProjectUuids()).isPresent(); @@ -166,14 +163,14 @@ public class ProjectMeasuresQueryFactoryTest { @Test public void convert_metric_to_lower_case() throws Exception { ProjectMeasuresQuery query = newProjectMeasuresQuery(asList( - Criterion.builder().setKey("NCLOC").setOperator(">").setValue("10").build(), - Criterion.builder().setKey("coVERage").setOperator("<=").setValue("80").build()), + Criterion.builder().setKey("NCLOC").setOperator(GT).setValue("10").build(), + Criterion.builder().setKey("coVERage").setOperator(LTE).setValue("80").build()), emptySet()); assertThat(query.getMetricCriteria()) .extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue) .containsOnly( - tuple("ncloc", Operator.GT, 10d), + tuple("ncloc", GT, 10d), tuple("coverage", Operator.LTE, 80d)); } @@ -184,30 +181,4 @@ public class ProjectMeasuresQueryFactoryTest { assertThat(result.getMetricCriteria()).isEmpty(); } - @Test - public void fail_when_not_double() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Value 'ten' is not a number"); - - newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue("ten").build()), - emptySet()); - } - - @Test - public void fail_when_no_operator() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Operator cannot be null for 'ncloc'"); - - newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(null).setValue("ten").build()), - emptySet()); - } - - @Test - public void fail_when_no_value() throws Exception { - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Value cannot be null for 'ncloc'"); - - newProjectMeasuresQuery(singletonList(Criterion.builder().setKey("ncloc").setOperator(">").setValue(null).build()), - emptySet()); - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java index 8fa05eae1a2..c6e0e6fef9e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ProjectMeasuresQueryValidatorTest.java @@ -35,11 +35,11 @@ import static org.sonar.api.measures.Metric.ValueType.INT; import static org.sonar.api.measures.Metric.ValueType.STRING; import static org.sonar.api.measures.Metric.ValueType.WORK_DUR; import static org.sonar.db.metric.MetricTesting.newMetricDto; +import static org.sonar.server.component.ws.FilterParser.Operator.EQ; +import static org.sonar.server.component.ws.FilterParser.Operator.GT; +import static org.sonar.server.component.ws.FilterParser.Operator.LT; +import static org.sonar.server.component.ws.FilterParser.Operator.LTE; import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.EQ; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.GT; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.LT; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.LTE; public class ProjectMeasuresQueryValidatorTest { diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java index abbd8c49ac2..931aeda2a49 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java @@ -40,7 +40,6 @@ import org.sonar.server.es.Facets; import org.sonar.server.es.SearchIdResult; import org.sonar.server.es.SearchOptions; import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; import org.sonar.server.permission.index.AuthorizationTypeSupport; import org.sonar.server.permission.index.PermissionIndexerDao; import org.sonar.server.permission.index.PermissionIndexerTester; @@ -58,6 +57,7 @@ import static org.sonar.api.measures.Metric.Level.WARN; import static org.sonar.db.component.ComponentTesting.newProjectDto; import static org.sonar.db.user.GroupTesting.newGroupDto; import static org.sonar.db.user.UserTesting.newUserDto; +import static org.sonar.server.component.ws.FilterParser.Operator; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURE; diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java index a549026fc58..1ce078b232f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresQueryTest.java @@ -28,7 +28,8 @@ import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; import static org.sonar.api.measures.Metric.Level.OK; -import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator.EQ; +import static org.sonar.server.component.ws.FilterParser.Operator; +import static org.sonar.server.component.ws.FilterParser.Operator.EQ; public class ProjectMeasuresQueryTest { @@ -63,6 +64,20 @@ public class ProjectMeasuresQueryTest { @Test public void fail_to_create_operator_from_unknown_value() throws Exception { expectedException.expect(IllegalArgumentException.class); - ProjectMeasuresQuery.Operator.valueOf("UNKNOWN"); + + Operator.valueOf("UNKNOWN"); + } + + @Test + public void default_sort_is_by_name() throws Exception { + assertThat(underTest.getSort()).isEqualTo("name"); + } + + @Test + public void fail_to_set_null_sort() throws Exception { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("Sort cannot be null"); + + underTest.setSort(null); } } -- cgit v1.2.3