]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3432 Support rule property types in annotations
authorDavid Gageot <david@gageot.net>
Fri, 6 Jul 2012 13:25:10 +0000 (15:25 +0200)
committerDavid Gageot <david@gageot.net>
Fri, 6 Jul 2012 13:55:27 +0000 (15:55 +0200)
sonar-check-api/src/main/java/org/sonar/check/RuleProperty.java
sonar-plugin-api/src/main/java/org/sonar/api/rules/AnnotationRuleParser.java
sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleParam.java
sonar-plugin-api/src/test/java/org/sonar/api/rules/AnnotationRuleParserTest.java

index efcf609eaba5f605654895a1fd9cb55622d6f0c6..44d1e91094a01aed05370c7623893fac52948bcc 100644 (file)
@@ -46,4 +46,13 @@ public @interface RuleProperty {
    * Optional default value.
    */
   String defaultValue() default "";
+
+  /**
+   * Optional type.
+   * See {@org.sonar.api.PropertyType} for possible values.
+   * If <code>type</code> is ommited, it is guessed from the type of the annotated field.
+   *
+   * @since 3.2
+   */
+  String type() default "";
 }
index f4fc44856380ff946a862a7314c86a8f34e24cf3..1d9a20bd9599ce1ede3426e7e47678b313341a26 100644 (file)
  */
 package org.sonar.api.rules;
 
-import java.lang.reflect.Field;
-import java.util.Collection;
-import java.util.List;
-
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
 import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.PropertyType;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.utils.AnnotationUtils;
 import org.sonar.check.Check;
 
-import com.google.common.collect.Lists;
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * @since 2.3
@@ -102,6 +103,15 @@ public final class AnnotationRuleParser implements ServerComponent {
       RuleParam param = rule.createParameter(fieldKey);
       param.setDescription(propertyAnnotation.description());
       param.setDefaultValue(propertyAnnotation.defaultValue());
+      if (!StringUtils.isBlank(propertyAnnotation.type())) {
+        try {
+          param.setType(PropertyType.valueOf(propertyAnnotation.type().trim()).name());
+        } catch (IllegalArgumentException e) {
+          throw new IllegalArgumentException("Invalid property type [" + propertyAnnotation.type() + "]", e);
+        }
+      } else {
+        param.setType(guessType(field.getType()).name());
+      }
     }
   }
 
@@ -113,4 +123,16 @@ public final class AnnotationRuleParser implements ServerComponent {
       param.setDescription(propertyAnnotation.description());
     }
   }
+
+  @VisibleForTesting
+  static PropertyType guessType(Class<?> type) {
+    if ((type == Integer.class) || (type == int.class)) {
+      return PropertyType.INTEGER;
+    } else if ((type == Float.class) || (type == float.class)) {
+      return PropertyType.FLOAT;
+    } else if ((type == Boolean.class) || (type == boolean.class)) {
+      return PropertyType.BOOLEAN;
+    }
+    return PropertyType.STRING;
+  }
 }
index aedafe0b7ff29862ef90a868b620075cb855df61..9000666568a27dbdfcf0e9603061b6b792eaaec7 100644 (file)
@@ -51,7 +51,7 @@ public class RuleParam {
   private String description;
 
   @Column(name = "param_type", updatable = true, nullable = true, length = 512)
-  private String type = "s";
+  private String type = "STRING";
 
   @Column(name = "default_value", updatable = true, nullable = true, length = 4000)
   private String defaultValue;
index ab71282c48e7f07ea040e9a4c999feb494190c45..cafb678c217b23a966192737f53b084e580908b3 100644 (file)
  */
 package org.sonar.api.rules;
 
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertThat;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.PropertyType;
+import org.sonar.check.IsoCategory;
+import org.sonar.check.Priority;
 
 import java.util.Collections;
 import java.util.List;
 
-import org.junit.Test;
-import org.sonar.check.IsoCategory;
-import org.sonar.check.Priority;
+import static org.fest.assertions.Assertions.assertThat;
 
 public class AnnotationRuleParserTest {
+  @org.junit.Rule
+  public final ExpectedException exception = ExpectedException.none();
 
   @Test
   public void ruleWithProperty() {
     List<Rule> rules = parseAnnotatedClass(RuleWithProperty.class);
-    assertThat(rules.size(), is(1));
+    assertThat(rules).hasSize(1);
     Rule rule = rules.get(0);
-    assertThat(rule.getKey(), is("foo"));
-    assertThat(rule.getName(), is("bar"));
-    assertThat(rule.getDescription(), is("Foo Bar"));
-    assertThat(rule.getSeverity(), is(RulePriority.BLOCKER));
-    assertThat(rule.getParams().size(), is(1));
+    assertThat(rule.getKey()).isEqualTo("foo");
+    assertThat(rule.getName()).isEqualTo("bar");
+    assertThat(rule.getDescription()).isEqualTo("Foo Bar");
+    assertThat(rule.getSeverity()).isEqualTo(RulePriority.BLOCKER);
+    assertThat(rule.getParams()).hasSize(1);
     RuleParam prop = rule.getParam("property");
-    assertThat(prop.getKey(), is("property"));
-    assertThat(prop.getDescription(), is("Ignore ?"));
-    assertThat(prop.getDefaultValue(), is("false"));
+    assertThat(prop.getKey()).isEqualTo("property");
+    assertThat(prop.getDescription()).isEqualTo("Ignore ?");
+    assertThat(prop.getDefaultValue()).isEqualTo("false");
+    assertThat(prop.getType()).isEqualTo(PropertyType.STRING.name());
+  }
+
+  @Test
+  public void ruleWithIntegerProperty() {
+    List<Rule> rules = parseAnnotatedClass(RuleWithIntegerProperty.class);
+
+    RuleParam prop = rules.get(0).getParam("property");
+    assertThat(prop.getDescription()).isEqualTo("Max");
+    assertThat(prop.getDefaultValue()).isEqualTo("12");
+    assertThat(prop.getType()).isEqualTo(PropertyType.INTEGER.name());
+  }
+
+  @Test
+  public void ruleWithTextProperty() {
+    List<Rule> rules = parseAnnotatedClass(RuleWithTextProperty.class);
+
+    RuleParam prop = rules.get(0).getParam("property");
+    assertThat(prop.getDescription()).isEqualTo("text");
+    assertThat(prop.getDefaultValue()).isEqualTo("Long text");
+    assertThat(prop.getType()).isEqualTo(PropertyType.TEXT.name());
+  }
+
+  @Test
+  public void should_reject_invalid_prroperty_types() {
+    exception.expect(IllegalArgumentException.class);
+    exception.expectMessage("Invalid property type [INVALID]");
+
+    parseAnnotatedClass(RuleWithInvalidPropertyType.class);
+  }
+
+  @Test
+  public void should_recognize_type() {
+    assertThat(AnnotationRuleParser.guessType(Integer.class)).isEqualTo(PropertyType.INTEGER);
+    assertThat(AnnotationRuleParser.guessType(int.class)).isEqualTo(PropertyType.INTEGER);
+    assertThat(AnnotationRuleParser.guessType(Float.class)).isEqualTo(PropertyType.FLOAT);
+    assertThat(AnnotationRuleParser.guessType(float.class)).isEqualTo(PropertyType.FLOAT);
+    assertThat(AnnotationRuleParser.guessType(Boolean.class)).isEqualTo(PropertyType.BOOLEAN);
+    assertThat(AnnotationRuleParser.guessType(boolean.class)).isEqualTo(PropertyType.BOOLEAN);
+    assertThat(AnnotationRuleParser.guessType(String.class)).isEqualTo(PropertyType.STRING);
+    assertThat(AnnotationRuleParser.guessType(Object.class)).isEqualTo(PropertyType.STRING);
   }
 
   @Test
   public void ruleWithoutNameNorDescription() {
     List<Rule> rules = parseAnnotatedClass(RuleWithoutNameNorDescription.class);
-    assertThat(rules.size(), is(1));
+    assertThat(rules).hasSize(1);
     Rule rule = rules.get(0);
-    assertThat(rule.getKey(), is("foo"));
-    assertThat(rule.getSeverity(), is(RulePriority.MAJOR));
-    assertThat(rule.getName(), is(nullValue()));
-    assertThat(rule.getDescription(), is(nullValue()));
+    assertThat(rule.getKey()).isEqualTo("foo");
+    assertThat(rule.getSeverity()).isEqualTo(RulePriority.MAJOR);
+    assertThat(rule.getName()).isNull();
+    assertThat(rule.getDescription()).isNull();
   }
 
   @Test
   public void ruleWithoutKey() {
     List<Rule> rules = parseAnnotatedClass(RuleWithoutKey.class);
-    assertThat(rules.size(), is(1));
+    assertThat(rules).hasSize(1);
     Rule rule = rules.get(0);
-    assertThat(rule.getKey(), is(RuleWithoutKey.class.getCanonicalName()));
-    assertThat(rule.getName(), is("foo"));
-    assertThat(rule.getDescription(), is(nullValue()));
-    assertThat(rule.getSeverity(), is(RulePriority.MAJOR));
+    assertThat(rule.getKey()).isEqualTo(RuleWithoutKey.class.getCanonicalName());
+    assertThat(rule.getName()).isEqualTo("foo");
+    assertThat(rule.getDescription()).isNull();
+    assertThat(rule.getSeverity()).isEqualTo(RulePriority.MAJOR);
   }
 
   @Test
   public void supportDeprecatedAnnotations() {
     List<Rule> rules = parseAnnotatedClass(Check.class);
-    assertThat(rules.size(), is(1));
+    assertThat(rules).hasSize(1);
     Rule rule = rules.get(0);
-    assertThat(rule.getKey(), is(Check.class.getCanonicalName()));
-    assertThat(rule.getName(), is(Check.class.getCanonicalName()));
-    assertThat(rule.getDescription(), is("Deprecated check"));
-    assertThat(rule.getSeverity(), is(RulePriority.BLOCKER));
+    assertThat(rule.getKey()).isEqualTo(Check.class.getCanonicalName());
+    assertThat(rule.getName()).isEqualTo(Check.class.getCanonicalName());
+    assertThat(rule.getDescription()).isEqualTo("Deprecated check");
+    assertThat(rule.getSeverity()).isEqualTo(RulePriority.BLOCKER);
   }
 
   private List<Rule> parseAnnotatedClass(Class annotatedClass) {
@@ -86,21 +129,38 @@ public class AnnotationRuleParserTest {
   }
 
   @org.sonar.check.Rule(name = "foo")
-  private class RuleWithoutKey {
+  static class RuleWithoutKey {
   }
 
   @org.sonar.check.Rule(key = "foo")
-  private class RuleWithoutNameNorDescription {
+  static class RuleWithoutNameNorDescription {
   }
 
   @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
-  private class RuleWithProperty {
+  static class RuleWithProperty {
     @org.sonar.check.RuleProperty(description = "Ignore ?", defaultValue = "false")
-    String property;
+    public String property;
   }
 
-  @org.sonar.check.Check(description = "Deprecated check", priority = Priority.BLOCKER, isoCategory = IsoCategory.Maintainability)
-  private class Check {
+  @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+  static class RuleWithIntegerProperty {
+    @org.sonar.check.RuleProperty(description = "Max", defaultValue = "12")
+    public Integer property;
   }
 
+  @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+  static class RuleWithTextProperty {
+    @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "TEXT")
+    public String property;
+  }
+
+  @org.sonar.check.Rule(key = "foo", name = "bar", description = "Foo Bar", priority = Priority.BLOCKER)
+  static class RuleWithInvalidPropertyType {
+    @org.sonar.check.RuleProperty(description = "text", defaultValue = "Long text", type = "INVALID")
+    public String property;
+  }
+
+  @org.sonar.check.Check(description = "Deprecated check", priority = Priority.BLOCKER, isoCategory = IsoCategory.Maintainability)
+  static class Check {
+  }
 }