]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2453 Update the way "FALSE-POSITIVE" reviews are managed
authorFabrice Bellingard <bellingard@gmail.com>
Thu, 26 May 2011 10:10:38 +0000 (12:10 +0200)
committerFabrice Bellingard <bellingard@gmail.com>
Thu, 26 May 2011 11:49:26 +0000 (13:49 +0200)
1- Update the DB, migration scripts & co.
2- Update the model, controller & co.
3- Update the WS Client

17 files changed:
plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/sensors/CloseReviewsDecoratorTest/shouldCloseReviewWithoutCorrespondingViolation-result.xml
plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews-result.xml
plugins/sonar-dbcleaner-plugin/src/test/resources/org/sonar/plugins/dbcleaner/purges/PurgeOrphanReviewsTest/purgeOrphanReviews.xml
sonar-core/src/main/java/org/sonar/jpa/entity/SchemaMigration.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/reviews_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb
sonar-server/src/main/webapp/WEB-INF/db/migrate/201_change_false_positive_on_reviews.rb [new file with mode: 0644]
sonar-testing-harness/src/main/resources/org/sonar/test/persistence/sonar-test.ddl
sonar-ws-client/src/main/java/org/sonar/wsclient/services/Review.java
sonar-ws-client/src/main/java/org/sonar/wsclient/services/ReviewQuery.java
sonar-ws-client/src/main/java/org/sonar/wsclient/unmarshallers/ReviewUnmarshaller.java
sonar-ws-client/src/test/java/org/sonar/wsclient/services/ReviewQueryTest.java
sonar-ws-client/src/test/java/org/sonar/wsclient/unmarshallers/ReviewUnmarshallerTest.java
sonar-ws-client/src/test/resources/reviews/reviews-2.8.json [new file with mode: 0644]
sonar-ws-client/src/test/resources/reviews/reviews-2.9.json [new file with mode: 0644]
sonar-ws-client/src/test/resources/reviews/reviews.json [deleted file]

index 49123b1a1a95f22ae8c00dd1087ce9fa6cc792a1..7b3d60ec42cac6a769954f17b08abb1b460cd218 100644 (file)
@@ -5,24 +5,24 @@
                        status="OPEN"
                        rule_failure_permanent_id="1"
                        resource_id="555"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
   <reviews
                        id="2"
                        status="CLOSED"
                        rule_failure_permanent_id="2"
                        resource_id="666"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
   <reviews
                        id="3"
                        status="OPEN"
                        rule_failure_permanent_id="3"
                        resource_id="666"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
   <reviews
                        id="4"
                        status="CLOSED"
                        rule_failure_permanent_id="2"
                        resource_id="666"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]" project_id="[null]"/>
 
 </dataset>
\ No newline at end of file
index 7680bdd39c0f62d53fb7172158a7e9ae9cbdf5de..50fc18b74c42bf8e901ed238640d3bee67d24968 100644 (file)
@@ -16,7 +16,7 @@
                        rule_failure_permanent_id="1"
                        resource_id="555"
                        project_id="1"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]"/>
                        
   <!--  Following must have been deleted
   <reviews
@@ -25,7 +25,7 @@
                        rule_failure_permanent_id="2"
                        resource_id="666"
                        project_id="2"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]"/>
   -->
                        
   <review_comments
index 01da1669b4007ff2d85f1b9ea29b2cf006afe128..6408b5a19477a0324d10726209ad204ab2ed8085 100644 (file)
                        rule_failure_permanent_id="1"
                        resource_id="555"
                        project_id="1"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]"/>
   <reviews
                        id="2"
                        status="CLOSED"
                        rule_failure_permanent_id="2"
                        resource_id="666"
                        project_id="2"
-                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" review_type="[null]" severity="[null]" resource_line="[null]"/>
+                       created_at="[null]" updated_at="[null]" user_id="[null]" assignee_id="[null]" title="[null]" false_positive="[null]" severity="[null]" resource_line="[null]"/>
                        
   <review_comments
                        id="1"
index c5d25eb586ff94d902d918c6e4f9e1cfce6edd5c..039029276d7315e9ec6dfaa3d06773704262341f 100644 (file)
@@ -40,7 +40,7 @@ public class SchemaMigration {
       - complete the Derby DDL file used for unit tests : sonar-testing-harness/src/main/resources/org/sonar/test/persistence/sonar-test.ddl
 
    */
-  public static final int LAST_VERSION = 200;
+  public static final int LAST_VERSION = 201;
 
   public final static String TABLE_NAME = "schema_migrations";
 
index 742b81c7d2f47804e3adec51028e0c94b98535a6..ddf519dca1e82868f86e296114ea1592a8d8bc5f 100644 (file)
@@ -123,7 +123,7 @@ class ReviewsController < ApplicationController
       violation.save!
     end
 
-    @review.review_type = (false_positive ? Review::TYPE_FALSE_POSITIVE : Review::TYPE_VIOLATION)
+    @review.false_positive = false_positive
     @review.assignee = nil
     @review.save!
     unless params[:comment].blank?
@@ -203,7 +203,7 @@ class ReviewsController < ApplicationController
       if violation.review.nil?
         violation.build_review(:user_id => current_user.id)
       end
-      violation.review.review_type=(false_positive ? Review::TYPE_FALSE_POSITIVE : Review::TYPE_VIOLATION)
+      violation.review.false_positive=false_positive
       violation.review.assignee=nil
       violation.review.save!
       violation.review.comments.create(:review_text => params[:comment], :user_id => current_user.id)
@@ -285,7 +285,7 @@ class ReviewsController < ApplicationController
   end
 
   def search_reviews
-    options = {'review_type' => 'VIOLATION'}
+    options = { 'false_positives' => 'without' }
     unless @statuses == ['']
       options['statuses']=@statuses.join(',')
     end
index 7fecb7d342ae3dc64a5be31b6f02b6fff8a95736..3951dc0edaf6c64483cd8d5dcc1e77f955a70f54 100644 (file)
@@ -27,14 +27,10 @@ class Review < ActiveRecord::Base
   belongs_to :rule_failure, :foreign_key => 'rule_failure_permanent_id', :primary_key => 'permanent_id'
   
   validates_presence_of :user, :message => "can't be empty"
-  validates_presence_of :review_type, :message => "can't be empty"
   validates_presence_of :status, :message => "can't be empty"
   
   before_save :assign_project
   
-  TYPE_VIOLATION = 'VIOLATION'
-  TYPE_FALSE_POSITIVE = 'FALSE_POSITIVE'
-  
   STATUS_OPEN = 'OPEN'
   STATUS_CLOSED = 'CLOSED'
     
@@ -90,11 +86,27 @@ class Review < ActiveRecord::Base
   def self.search(options={})
     conditions=[]
     values={}
+    
+    # --- 'review_type' is deprecated since 2.9 ---
+    # Following code just for backward compatibility
+    review_type = options['review_type']
+    if review_type
+      conditions << 'false_positive=:false_positive'
+      if review_type == 'FALSE_POSITIVE'
+        values[:false_positive]=true
+      else
+        values[:false_positive]=false
+      end
+    end
+    # --- End of code for backward compatibility code ---
       
-    review_type = options['review_type'].split(',') if options['review_type']
-    if review_type && review_type.size>0 && !review_type[0].blank?
-      conditions << 'review_type in (:review_type)'
-      values[:review_type]=review_type
+    false_positives = options['false_positives']
+    if false_positives == "only"
+      conditions << 'false_positive=:false_positive'
+      values[:false_positive]=true
+    elsif false_positives == "without"
+      conditions << 'false_positive=:false_positive'
+      values[:false_positive]=false    
     end
     
     ids=options['ids'].split(',') if options['ids']
@@ -202,7 +214,7 @@ class Review < ActiveRecord::Base
       xml.author(user.login)
       xml.assignee(assignee.login) if assignee
       xml.title(title)
-      xml.type(review_type)
+      xml.falsePositive(false_positive)
       xml.status(status)
       xml.severity(severity)
       xml.resource(resource.kee)  if resource
@@ -235,7 +247,7 @@ class Review < ActiveRecord::Base
     json['author'] = user.login
     json['assignee'] = assignee.login if assignee
     json['title'] = title if title
-    json['type'] = review_type
+    json['falsePositive'] = false_positive
     json['status'] = status
     json['severity'] = severity
     json['resource'] = resource.kee if resource
index eda6220717f18a32ef4a636e37105658aec9665d..0ce59a962d95225835bab069436540cad9d85f43 100644 (file)
@@ -102,8 +102,7 @@ class RuleFailure < ActiveRecord::Base
   def build_review(options={})
     if review.nil?
       self.review=Review.new(
-        {:review_type => Review::TYPE_VIOLATION,
-        :status => Review::STATUS_OPEN,
+        {:status => Review::STATUS_OPEN,
         :severity => Sonar::RulePriority.to_s(failure_level),
         :resource_line => line,
         :resource => snapshot.resource,
diff --git a/sonar-server/src/main/webapp/WEB-INF/db/migrate/201_change_false_positive_on_reviews.rb b/sonar-server/src/main/webapp/WEB-INF/db/migrate/201_change_false_positive_on_reviews.rb
new file mode 100644 (file)
index 0000000..d2c2312
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 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
+#
+
+#
+# Sonar 2.9
+#
+class ChangeFalsePositiveOnReviews < ActiveRecord::Migration
+
+  def self.up
+    add_column 'reviews', 'false_positive', :boolean, :null => true, :default => false
+    Review.reset_column_information
+    
+    Review.find(:all).each do |review|
+      review.false_positive= (review.review_type == 'FALSE_POSITIVE')
+      review.save!
+    end
+    
+    remove_column 'reviews', 'review_type'
+    Review.reset_column_information
+  end
+
+end
index d7e6a8484813d96652597f6f742a338df1633b8f..2391427880f5c768cdb7e5ce875cf65ad5cd9d4e 100644 (file)
@@ -489,13 +489,13 @@ CREATE TABLE REVIEWS (
   USER_ID INTEGER,
   ASSIGNEE_ID INTEGER,
   TITLE VARCHAR(500),
-  REVIEW_TYPE VARCHAR(10),
   STATUS VARCHAR(10),
   SEVERITY VARCHAR(10),
   RULE_FAILURE_PERMANENT_ID INTEGER,
   PROJECT_ID INTEGER,
   RESOURCE_ID INTEGER,
   RESOURCE_LINE INTEGER,
+  FALSE_POSITIVE SMALLINT,
   primary key (id)
 );
 
index eef8c5a475b0d9ab7500c0618cce4779f4329157..91c84411c831de0121c30183e907f437b9b176c2 100644 (file)
@@ -39,6 +39,7 @@ public class Review extends Model {
   private String severity = null;
   private String resourceKee = null;
   private Integer line = null;
+  private Boolean falsePositive = null;
   private List<Review.Comment> comments = new ArrayList<Review.Comment>();
 
   /**
@@ -138,6 +139,7 @@ public class Review extends Model {
   }
 
   /**
+   * @deprecated since 2.9. Use {@link #getFalsePositive()} instead.
    * @return the type
    */
   public String getType() {
@@ -145,11 +147,18 @@ public class Review extends Model {
   }
 
   /**
+   * @deprecated since 2.9. Use {@link #setFalsePositive(Boolean)} instead.
    * @param s
    *          the type to set
    */
   public Review setType(String s) {
     this.type = s;
+    // the following code is only here to ensure backward compatibility with 2.8
+    if ("FALSE_POSITIVE".equals(type)) {
+      falsePositive = Boolean.TRUE;
+    } else if ("VIOLATION".equals(type)) {
+      falsePositive = Boolean.FALSE;
+    }
     return this;
   }
 
@@ -217,6 +226,24 @@ public class Review extends Model {
     return this;
   }
 
+  /**
+   * @since 2.9
+   * @return the falsePositive
+   */
+  public Boolean getFalsePositive() {
+    return falsePositive;
+  }
+
+  /**
+   * @since 2.9
+   * @param falsePositive
+   *          true if false positive
+   */
+  public Review setFalsePositive(Boolean falsePositive) {
+    this.falsePositive = falsePositive;
+    return this;
+  }
+
   /**
    * @return the comments
    */
index dda32f50a08492b0d6d6ecdfc2bf366d2285fe58..a6701d4a18e508b60f4f5146651a940d881f90cd 100644 (file)
@@ -29,6 +29,7 @@ public class ReviewQuery extends Query<Review> {
   public static final String OUTPUT_PLAIN = "PLAIN";
   public static final String OUTPUT_HTML = "HTML";
 
+  @Deprecated
   private String reviewType;
   private Long id;
   private Long[] ids;
@@ -39,18 +40,21 @@ public class ReviewQuery extends Query<Review> {
   private String[] authorLoginsOrIds;
   private String[] assigneeLoginsOrIds;
   private String output;
+  private String falsePositives;
 
   public ReviewQuery() {
   }
 
   /**
-   * @return the reviewType
+   * @deprecated since 2.9
+   * @return NULL
    */
   public String getReviewType() {
     return reviewType;
   }
 
   /**
+   * @deprecated since 2.9
    * @param reviewType
    *          the reviewType to set
    */
@@ -122,8 +126,7 @@ public class ReviewQuery extends Query<Review> {
     this.severities = severities;
     return this;
   }
-  
-  
+
   /**
    * @return the projectKeysOrIds
    */
@@ -131,16 +134,15 @@ public class ReviewQuery extends Query<Review> {
     return projectKeysOrIds;
   }
 
-  
   /**
-   * @param projectKeysOrIds the projectKeysOrIds to set
+   * @param projectKeysOrIds
+   *          the projectKeysOrIds to set
    */
   public ReviewQuery setProjectKeysOrIds(String... projectKeysOrIds) {
     this.projectKeysOrIds = projectKeysOrIds;
     return this;
   }
 
-  
   /**
    * @return the resourceKeysOrIds
    */
@@ -148,16 +150,15 @@ public class ReviewQuery extends Query<Review> {
     return resourceKeysOrIds;
   }
 
-  
   /**
-   * @param resourceKeysOrIds the resourceKeysOrIds to set
+   * @param resourceKeysOrIds
+   *          the resourceKeysOrIds to set
    */
   public ReviewQuery setResourceKeysOrIds(String... resourceKeysOrIds) {
     this.resourceKeysOrIds = resourceKeysOrIds;
     return this;
   }
 
-  
   /**
    * @return the authorLoginsOrIds
    */
@@ -165,16 +166,15 @@ public class ReviewQuery extends Query<Review> {
     return authorLoginsOrIds;
   }
 
-  
   /**
-   * @param authorLoginsOrIds the authorLoginsOrIds to set
+   * @param authorLoginsOrIds
+   *          the authorLoginsOrIds to set
    */
   public ReviewQuery setAuthorLoginsOrIds(String... authorLoginsOrIds) {
     this.authorLoginsOrIds = authorLoginsOrIds;
     return this;
   }
 
-  
   /**
    * @return the assigneeLoginsOrIds
    */
@@ -182,9 +182,9 @@ public class ReviewQuery extends Query<Review> {
     return assigneeLoginsOrIds;
   }
 
-  
   /**
-   * @param assigneeLoginsOrIds the assigneeLoginsOrIds to set
+   * @param assigneeLoginsOrIds
+   *          the assigneeLoginsOrIds to set
    */
   public ReviewQuery setAssigneeLoginsOrIds(String... assigneeLoginsOrIds) {
     this.assigneeLoginsOrIds = assigneeLoginsOrIds;
@@ -198,11 +198,42 @@ public class ReviewQuery extends Query<Review> {
     return output;
   }
 
+  /**
+   * 
+   * @param output
+   *          the output
+   */
   public ReviewQuery setOutput(String output) {
     this.output = output;
     return this;
   }
 
+  /**
+   * @since 2.9
+   * @return the false_positives
+   */
+  public String getFalsePositives() {
+    return falsePositives;
+  }
+
+  /**
+   * Sets the 'false_positives' parameter that can be:
+   * <ul>
+   * <li>only</li>
+   * <li>with</li>
+   * <li>without</li>
+   * </ul>
+   * , 'with' being the default one on the server side. <br>
+   * <br>
+   * 
+   * @since 2.9
+   * @param falsePositives
+   *          the false_positives
+   */
+  public void setFalsePositives(String falsePositives) {
+    this.falsePositives = falsePositives;
+  }
+
   @Override
   public String getUrl() {
     StringBuilder url = new StringBuilder(BASE_URL);
@@ -212,7 +243,6 @@ public class ReviewQuery extends Query<Review> {
     } else if (ids != null) {
       appendUrlParameter(url, "ids", ids);
     }
-    appendUrlParameter(url, "review_type", reviewType);
     appendUrlParameter(url, "statuses", statuses);
     appendUrlParameter(url, "severities", severities);
     appendUrlParameter(url, "projects", projectKeysOrIds);
@@ -220,6 +250,11 @@ public class ReviewQuery extends Query<Review> {
     appendUrlParameter(url, "authors", authorLoginsOrIds);
     appendUrlParameter(url, "assignees", assigneeLoginsOrIds);
     appendUrlParameter(url, "output", output);
+    appendUrlParameter(url, "false_positives", falsePositives);
+    if (falsePositives == null && reviewType != null) {
+      // Use of the 2.8 deprecated API: handle backward compatibility
+      appendUrlParameter(url, "review_type", reviewType);
+    }
 
     return url.toString();
   }
index cdaf3c2bb63dbb3b9f093d17bcf64ff34c9fa555..449d45b3f3bff87bb6572990c15a6e45322852cc 100644 (file)
@@ -38,11 +38,12 @@ public class ReviewUnmarshaller extends AbstractUnmarshaller<Review> {
     review.setAuthorLogin(utils.getString(json, "author"));
     review.setAssigneeLogin(utils.getString(json, "assignee"));
     review.setTitle(utils.getString(json, "title"));
-    review.setType(utils.getString(json, "type"));
     review.setStatus(utils.getString(json, "status"));
     review.setSeverity(utils.getString(json, "severity"));
     review.setResourceKee(utils.getString(json, "resource"));
     review.setLine(utils.getInteger(json, "line"));
+    review.setFalsePositive(utils.getBoolean(json, "falsePositive"));
+    review.setType(utils.getString(json, "type"));
 
     Object comments = utils.getField(json, "comments");
     if (comments != null) {
index c347fac60b3588e087a153f063fc35a10d8354fe..ddb58c41d836438ef0d15f26847aa6df0f14d4c4 100644 (file)
@@ -39,12 +39,23 @@ public class ReviewQueryTest extends QueryTestCase {
 
   @Test
   public void resourceTreeViolations() {
+    ReviewQuery query = new ReviewQuery();
+    query.setIds(10L, 11L).setStatuses("OPEN").setSeverities("MINOR", "INFO").setProjectKeysOrIds("com.sonar.foo:bar")
+        .setResourceKeysOrIds("2", "3").setAuthorLoginsOrIds("20").setAssigneeLoginsOrIds("admin").setOutput("html")
+        .setFalsePositives("without");
+    assertThat(
+        query.getUrl(),
+        is("/api/reviews?ids=10,11&statuses=OPEN&severities=MINOR,INFO&projects=com.sonar.foo%3Abar&resources=2,3&authors=20&assignees=admin&output=html&false_positives=without&"));
+  }
+
+  @Test
+  public void resourceTreeViolationsForSonar2_8() {
     ReviewQuery query = new ReviewQuery();
     query.setIds(10L, 11L).setReviewType("FALSE_POSITIVE").setStatuses("OPEN").setSeverities("MINOR", "INFO")
         .setProjectKeysOrIds("com.sonar.foo:bar").setResourceKeysOrIds("2", "3").setAuthorLoginsOrIds("20").setAssigneeLoginsOrIds("admin")
         .setOutput("html");
     assertThat(
         query.getUrl(),
-        is("/api/reviews?ids=10,11&review_type=FALSE_POSITIVE&statuses=OPEN&severities=MINOR,INFO&projects=com.sonar.foo%3Abar&resources=2,3&authors=20&assignees=admin&output=html&"));
+        is("/api/reviews?ids=10,11&statuses=OPEN&severities=MINOR,INFO&projects=com.sonar.foo%3Abar&resources=2,3&authors=20&assignees=admin&output=html&review_type=FALSE_POSITIVE&"));
   }
 }
index 22a6ae0ad48fc0dfc26111a2b5baf34bb5f049ec..d3f543b984cf984aa0b514c895eabdfd27b9cfce 100644 (file)
@@ -33,14 +33,49 @@ import org.sonar.wsclient.services.Review.Comment;
 public class ReviewUnmarshallerTest extends UnmarshallerTestCase {
 
   @Test
-  public void testToModels() {
+  public void testEmptyJSON() {
     Review review = new ReviewUnmarshaller().toModel("[]");
     assertThat(review, nullValue());
+  }
+
+  @Test
+  public void testToModels() {
+    List<Review> reviews = new ReviewUnmarshaller().toModels(loadFile("/reviews/reviews-2.9.json"));
+    assertThat(reviews.size(), is(2));
+
+    Review review = reviews.get(0);
+    assertThat(review.getId(), is(3L));
+    assertNotNull(review.getCreatedAt());
+    assertNotNull(review.getUpdatedAt());
+    assertThat(review.getAuthorLogin(), is("admin"));
+    assertThat(review.getAssigneeLogin(), is("admin"));
+    assertThat(review.getTitle(), is("'static' modifier out of order with the JLS suggestions."));
+    assertThat(review.getFalsePositive(), is(Boolean.FALSE));
+    assertThat(review.getStatus(), is("OPEN"));
+    assertThat(review.getSeverity(), is("MINOR"));
+    assertThat(review.getResourceKee(), is("org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReaderConfiguration"));
+    assertThat(review.getLine(), is(33));
+    List<Comment> comments = review.getComments();
+    assertThat(comments.size(), is(4));
+    Comment comment = comments.get(0);
+    assertNotNull(comment.getUpdatedAt());
+    assertThat(comment.getAuthorLogin(), is("admin"));
+    assertThat(comment.getText(), is("This is a review.<br/>And this is on multiple lines...<br/><br/><code>Wouhou!!!!!</code>"));
 
-    List<Review> reviews = new ReviewUnmarshaller().toModels(loadFile("/reviews/reviews.json"));
+    review = reviews.get(1);
+    assertThat(review.getAssigneeLogin(), nullValue());
+    assertThat(review.getFalsePositive(), is(Boolean.TRUE));
+  }
+
+  /*
+   * Test Unmarshaller with JSON data received from a Sonar 2.8
+   */
+  @Test
+  public void testToModelsForSonar2_8() {
+    List<Review> reviews = new ReviewUnmarshaller().toModels(loadFile("/reviews/reviews-2.8.json"));
     assertThat(reviews.size(), is(2));
 
-    review = reviews.get(0);
+    Review review = reviews.get(0);
     assertThat(review.getAssigneeLogin(), nullValue());
 
     review = reviews.get(1);
diff --git a/sonar-ws-client/src/test/resources/reviews/reviews-2.8.json b/sonar-ws-client/src/test/resources/reviews/reviews-2.8.json
new file mode 100644 (file)
index 0000000..83a90bb
--- /dev/null
@@ -0,0 +1 @@
+[{"id":9,"createdAt":"2011-04-27T14:37:20+0200","updatedAt":"2011-04-27T14:37:20+0200","author":"admin","title":"New exception is thrown in catch block, original stack trace may be lost","type":"VIOLATION","status":"OPEN","severity":"MAJOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReader","line":84,"comments":[{"author":"admin","updatedAt":"2011-04-27T14:37:20+0200","text":"Wazzaaaa"}]},{"id":3,"createdAt":"2011-04-26T15:44:42+0200","updatedAt":"2011-04-26T15:44:42+0200","author":"admin","assignee":"admin","title":"'static' modifier out of order with the JLS suggestions.","type":"VIOLATION","status":"OPEN","severity":"MINOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReaderConfiguration","line":33,"comments":[{"author":"admin","updatedAt":"2011-04-26T15:44:42+0200","text":"This is a review.<br/>And this is on multiple lines...<br/><br/><code>Wouhou!!!!!</code>"},{"author":"admin","updatedAt":"2011-04-26T17:10:19+0200","text":"<em>Bold on multiple line?</em>"},{"author":"admin","updatedAt":"2011-04-26T17:11:02+0200","text":"And the bullets:<br/><ul><li>1 bullet</li>\n<li>2 bullets</li></ul>"},{"author":"admin","updatedAt":"2011-04-26T17:27:37+0200","text":"Wazzaa"}]}]
\ No newline at end of file
diff --git a/sonar-ws-client/src/test/resources/reviews/reviews-2.9.json b/sonar-ws-client/src/test/resources/reviews/reviews-2.9.json
new file mode 100644 (file)
index 0000000..371a151
--- /dev/null
@@ -0,0 +1 @@
+[{"id":3,"createdAt":"2011-04-26T15:44:42+0200","updatedAt":"2011-04-26T15:44:42+0200","author":"admin","assignee":"admin","title":"'static' modifier out of order with the JLS suggestions.","falsePositive":false,"status":"OPEN","severity":"MINOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReaderConfiguration","line":33,"comments":[{"author":"admin","updatedAt":"2011-04-26T15:44:42+0200","text":"This is a review.<br/>And this is on multiple lines...<br/><br/><code>Wouhou!!!!!</code>"},{"author":"admin","updatedAt":"2011-04-26T17:10:19+0200","text":"<em>Bold on multiple line?</em>"},{"author":"admin","updatedAt":"2011-04-26T17:11:02+0200","text":"And the bullets:<br/><ul><li>1 bullet</li>\n<li>2 bullets</li></ul>"},{"author":"admin","updatedAt":"2011-04-26T17:27:37+0200","text":"Wazzaa"}]},{"id":9,"createdAt":"2011-04-27T14:37:20+0200","updatedAt":"2011-04-27T14:37:20+0200","author":"admin","title":"New exception is thrown in catch block, original stack trace may be lost","falsePositive":true,"status":"OPEN","severity":"MAJOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReader","line":84,"comments":[{"author":"admin","updatedAt":"2011-04-27T14:37:20+0200","text":"Wazzaaaa"}]}]
\ No newline at end of file
diff --git a/sonar-ws-client/src/test/resources/reviews/reviews.json b/sonar-ws-client/src/test/resources/reviews/reviews.json
deleted file mode 100644 (file)
index 83a90bb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-[{"id":9,"createdAt":"2011-04-27T14:37:20+0200","updatedAt":"2011-04-27T14:37:20+0200","author":"admin","title":"New exception is thrown in catch block, original stack trace may be lost","type":"VIOLATION","status":"OPEN","severity":"MAJOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReader","line":84,"comments":[{"author":"admin","updatedAt":"2011-04-27T14:37:20+0200","text":"Wazzaaaa"}]},{"id":3,"createdAt":"2011-04-26T15:44:42+0200","updatedAt":"2011-04-26T15:44:42+0200","author":"admin","assignee":"admin","title":"'static' modifier out of order with the JLS suggestions.","type":"VIOLATION","status":"OPEN","severity":"MINOR","resource":"org.codehaus.sonar:sonar-channel:org.sonar.channel.CodeReaderConfiguration","line":33,"comments":[{"author":"admin","updatedAt":"2011-04-26T15:44:42+0200","text":"This is a review.<br/>And this is on multiple lines...<br/><br/><code>Wouhou!!!!!</code>"},{"author":"admin","updatedAt":"2011-04-26T17:10:19+0200","text":"<em>Bold on multiple line?</em>"},{"author":"admin","updatedAt":"2011-04-26T17:11:02+0200","text":"And the bullets:<br/><ul><li>1 bullet</li>\n<li>2 bullets</li></ul>"},{"author":"admin","updatedAt":"2011-04-26T17:27:37+0200","text":"Wazzaa"}]}]
\ No newline at end of file