LCOV - code coverage report
Current view: top level - entities - Comment.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 98 131 74.8 %
Date: 2022-11-19 15:00:39 Functions: 32 41 78.0 %

          Line data    Source code
       1             : // Copyright (C) 2016 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.entities;
      16             : 
      17             : import com.google.common.base.MoreObjects;
      18             : import com.google.common.base.MoreObjects.ToStringHelper;
      19             : import com.google.gerrit.common.Nullable;
      20             : import java.sql.Timestamp;
      21             : import java.time.Instant;
      22             : import java.util.Comparator;
      23             : import java.util.Objects;
      24             : import org.eclipse.jgit.lib.AnyObjectId;
      25             : import org.eclipse.jgit.lib.ObjectId;
      26             : 
      27             : /**
      28             :  * This class is a base class that can be extended by the different types of inline comment
      29             :  * entities.
      30             :  *
      31             :  * <p>Changing fields in this class changes the storage format of inline comments in NoteDb and may
      32             :  * require a corresponding data migration (adding new optional fields is generally okay).
      33             :  *
      34             :  * <p>Consider updating {@link #getCommentFieldApproximateSize()} when adding/changing fields.
      35             :  */
      36             : public abstract class Comment {
      37         103 :   public enum Status {
      38         103 :     DRAFT('d'),
      39             : 
      40         103 :     PUBLISHED('P');
      41             : 
      42             :     private final char code;
      43             : 
      44         103 :     Status(char c) {
      45         103 :       code = c;
      46         103 :     }
      47             : 
      48             :     public char getCode() {
      49           0 :       return code;
      50             :     }
      51             : 
      52             :     @Nullable
      53             :     public static Status forCode(char c) {
      54           0 :       for (Status s : Status.values()) {
      55           0 :         if (s.code == c) {
      56           0 :           return s;
      57             :         }
      58             :       }
      59           0 :       return null;
      60             :     }
      61             :   }
      62             : 
      63             :   public static final class Key {
      64             :     public String uuid;
      65             :     public String filename;
      66             :     public int patchSetId;
      67             : 
      68             :     public Key(Key k) {
      69          12 :       this(k.uuid, k.filename, k.patchSetId);
      70          12 :     }
      71             : 
      72          30 :     public Key(String uuid, String filename, int patchSetId) {
      73          30 :       this.uuid = uuid;
      74          30 :       this.filename = filename;
      75          30 :       this.patchSetId = patchSetId;
      76          30 :     }
      77             : 
      78             :     @Override
      79             :     public String toString() {
      80           0 :       return MoreObjects.toStringHelper(this)
      81           0 :           .add("uuid", uuid)
      82           0 :           .add("filename", filename)
      83           0 :           .add("patchSetId", patchSetId)
      84           0 :           .toString();
      85             :     }
      86             : 
      87             :     @Override
      88             :     public boolean equals(Object o) {
      89          24 :       if (o instanceof Key) {
      90          24 :         Key k = (Key) o;
      91          24 :         return Objects.equals(uuid, k.uuid)
      92          24 :             && Objects.equals(filename, k.filename)
      93             :             && patchSetId == k.patchSetId;
      94             :       }
      95           0 :       return false;
      96             :     }
      97             : 
      98             :     @Override
      99             :     public int hashCode() {
     100          29 :       return Objects.hash(uuid, filename, patchSetId);
     101             :     }
     102             :   }
     103             : 
     104             :   public static final class Identity {
     105             :     int id;
     106             : 
     107          30 :     public Identity(Account.Id id) {
     108          30 :       this.id = id.get();
     109          30 :     }
     110             : 
     111             :     public Account.Id getId() {
     112          29 :       return Account.id(id);
     113             :     }
     114             : 
     115             :     @Override
     116             :     public boolean equals(Object o) {
     117           2 :       if (o instanceof Identity) {
     118           2 :         return id == ((Identity) o).id;
     119             :       }
     120           0 :       return false;
     121             :     }
     122             : 
     123             :     @Override
     124             :     public int hashCode() {
     125          26 :       return Objects.hash(id);
     126             :     }
     127             : 
     128             :     @Override
     129             :     public String toString() {
     130           0 :       return MoreObjects.toStringHelper(this).add("id", id).toString();
     131             :     }
     132             :   }
     133             : 
     134             :   /**
     135             :    * The Range class defines continuous range of character.
     136             :    *
     137             :    * <p>The pair (startLine, startChar) defines the first character in the range. The pair (endLine,
     138             :    * endChar) defines the first character AFTER the range (i.e. it doesn't belong the range).
     139             :    * (endLine, endChar) must be a valid character inside text, except EOF case.
     140             :    *
     141             :    * <p>Special cases:
     142             :    *
     143             :    * <ul>
     144             :    *   <li>Zero length range: (startLine, startChar) = (endLine, endChar). Range defines insert
     145             :    *       position right before the (startLine, startChar) character (for {@link FixReplacement})
     146             :    *   <li>EOF case - range includes the last character in the file:
     147             :    *       <ul>
     148             :    *         <li>if a file ends with EOL mark, then (endLine, endChar) = (num_of_lines + 1, 0)
     149             :    *         <li>if a file doesn't end with EOL mark, then (endLine, endChar) = (num_of_lines,
     150             :    *             num_of_chars_in_last_line)
     151             :    *       </ul>
     152             :    * </ul>
     153             :    */
     154             :   public static final class Range implements Comparable<Range> {
     155          14 :     private static final Comparator<Range> RANGE_COMPARATOR =
     156          14 :         Comparator.<Range>comparingInt(range -> range.startLine)
     157          14 :             .thenComparingInt(range -> range.startChar)
     158          14 :             .thenComparingInt(range -> range.endLine)
     159          14 :             .thenComparingInt(range -> range.endChar);
     160             : 
     161             :     public int startLine; // 1-based
     162             :     public int startChar; // 0-based
     163             :     public int endLine; // 1-based
     164             :     public int endChar; // 0-based
     165             : 
     166             :     public Range(Range r) {
     167           3 :       this(r.startLine, r.startChar, r.endLine, r.endChar);
     168           3 :     }
     169             : 
     170             :     public Range(com.google.gerrit.extensions.client.Comment.Range r) {
     171          12 :       this(r.startLine, r.startCharacter, r.endLine, r.endCharacter);
     172          12 :     }
     173             : 
     174          14 :     public Range(int startLine, int startChar, int endLine, int endChar) {
     175          14 :       this.startLine = startLine;
     176          14 :       this.startChar = startChar;
     177          14 :       this.endLine = endLine;
     178          14 :       this.endChar = endChar;
     179          14 :     }
     180             : 
     181             :     @Override
     182             :     public boolean equals(Object o) {
     183           2 :       if (o instanceof Range) {
     184           2 :         Range r = (Range) o;
     185           2 :         return startLine == r.startLine
     186             :             && startChar == r.startChar
     187             :             && endLine == r.endLine
     188             :             && endChar == r.endChar;
     189             :       }
     190           1 :       return false;
     191             :     }
     192             : 
     193             :     @Override
     194             :     public int hashCode() {
     195          10 :       return Objects.hash(startLine, startChar, endLine, endChar);
     196             :     }
     197             : 
     198             :     @Override
     199             :     public String toString() {
     200           0 :       return MoreObjects.toStringHelper(this)
     201           0 :           .add("startLine", startLine)
     202           0 :           .add("startChar", startChar)
     203           0 :           .add("endLine", endLine)
     204           0 :           .add("endChar", endChar)
     205           0 :           .toString();
     206             :     }
     207             : 
     208             :     @Override
     209             :     public int compareTo(Range otherRange) {
     210           3 :       return RANGE_COMPARATOR.compare(this, otherRange);
     211             :     }
     212             :   }
     213             : 
     214             :   public Key key;
     215             :   /** The line number (1-based) to which the comment refers, or 0 for a file comment. */
     216             :   public int lineNbr;
     217             : 
     218             :   public Identity author;
     219             :   protected Identity realAuthor;
     220             : 
     221             :   // TODO(issue-15525): Migrate this field from Timestamp to Instant
     222             :   public Timestamp writtenOn;
     223             : 
     224             :   public short side;
     225             :   public String message;
     226             :   public String parentUuid;
     227             :   public Range range;
     228             :   public String tag;
     229             : 
     230             :   /**
     231             :    * Hex commit SHA1 of the commit of the patchset to which this comment applies. Other classes call
     232             :    * this "commitId", but this class uses the old ReviewDb term "revId", and this field name is
     233             :    * serialized into JSON in NoteDb, so it can't easily be changed. Callers do not access this field
     234             :    * directly, and instead use the public getter/setter that wraps an ObjectId.
     235             :    */
     236             :   private String revId;
     237             : 
     238             :   public String serverId;
     239             : 
     240             :   public Comment(Comment c) {
     241           4 :     this(new Key(c.key), c.author.getId(), c.writtenOn.toInstant(), c.side, c.message, c.serverId);
     242           4 :     this.lineNbr = c.lineNbr;
     243           4 :     this.realAuthor = c.realAuthor;
     244           4 :     this.parentUuid = c.parentUuid;
     245           4 :     this.range = c.range != null ? new Range(c.range) : null;
     246           4 :     this.tag = c.tag;
     247           4 :     this.revId = c.revId;
     248           4 :   }
     249             : 
     250             :   public Comment(
     251          30 :       Key key, Account.Id author, Instant writtenOn, short side, String message, String serverId) {
     252          30 :     this.key = key;
     253          30 :     this.author = new Comment.Identity(author);
     254          30 :     this.realAuthor = this.author;
     255          30 :     this.writtenOn = Timestamp.from(writtenOn);
     256          30 :     this.side = side;
     257          30 :     this.message = message;
     258          30 :     this.serverId = serverId;
     259          30 :   }
     260             : 
     261             :   public void setWrittenOn(Instant writtenOn) {
     262           3 :     this.writtenOn = Timestamp.from(writtenOn);
     263           3 :   }
     264             : 
     265             :   public void setLineNbrAndRange(
     266             :       Integer lineNbr, com.google.gerrit.extensions.client.Comment.Range range) {
     267          28 :     this.lineNbr = range != null ? range.endLine : lineNbr != null ? lineNbr : 0;
     268          28 :     if (range != null) {
     269           9 :       this.range = new Comment.Range(range);
     270             :     }
     271          28 :   }
     272             : 
     273             :   public void setRange(CommentRange range) {
     274           1 :     this.range = range != null ? range.asCommentRange() : null;
     275           1 :   }
     276             : 
     277             :   @Nullable
     278             :   public ObjectId getCommitId() {
     279          29 :     return revId != null ? ObjectId.fromString(revId) : null;
     280             :   }
     281             : 
     282             :   public void setCommitId(@Nullable AnyObjectId commitId) {
     283          29 :     this.revId = commitId != null ? commitId.name() : null;
     284          29 :   }
     285             : 
     286             :   public void setRealAuthor(Account.Id id) {
     287          29 :     realAuthor = id != null && id.get() != author.id ? new Comment.Identity(id) : null;
     288          29 :   }
     289             : 
     290             :   public Identity getRealAuthor() {
     291          29 :     return realAuthor != null ? realAuthor : author;
     292             :   }
     293             : 
     294             :   /**
     295             :    * Returns the comment's approximate size. This is used to enforce size limits and should
     296             :    * therefore include all unbounded fields (e.g. String-s).
     297             :    */
     298             :   protected int getCommentFieldApproximateSize() {
     299          23 :     return nullableLength(message, parentUuid, tag, revId, serverId)
     300          23 :         + (key != null ? nullableLength(key.filename, key.uuid) : 0);
     301             :   }
     302             : 
     303             :   public abstract int getApproximateSize();
     304             : 
     305             :   static int nullableLength(String... strings) {
     306          23 :     int length = 0;
     307          23 :     for (String s : strings) {
     308          23 :       length += s == null ? 0 : s.length();
     309             :     }
     310          23 :     return length;
     311             :   }
     312             : 
     313             :   @Override
     314             :   public boolean equals(Object o) {
     315          14 :     if (!(o instanceof Comment)) {
     316           0 :       return false;
     317             :     }
     318          14 :     Comment c = (Comment) o;
     319          14 :     return Objects.equals(key, c.key)
     320             :         && lineNbr == c.lineNbr
     321           2 :         && Objects.equals(author, c.author)
     322           2 :         && Objects.equals(realAuthor, c.realAuthor)
     323           2 :         && Objects.equals(writtenOn, c.writtenOn)
     324             :         && side == c.side
     325           2 :         && Objects.equals(message, c.message)
     326           2 :         && Objects.equals(parentUuid, c.parentUuid)
     327           2 :         && Objects.equals(range, c.range)
     328           2 :         && Objects.equals(tag, c.tag)
     329           2 :         && Objects.equals(revId, c.revId)
     330          14 :         && Objects.equals(serverId, c.serverId);
     331             :   }
     332             : 
     333             :   @Override
     334             :   public int hashCode() {
     335          26 :     return Objects.hash(
     336             :         key,
     337          26 :         lineNbr,
     338             :         author,
     339             :         realAuthor,
     340             :         writtenOn,
     341          26 :         side,
     342             :         message,
     343             :         parentUuid,
     344             :         range,
     345             :         tag,
     346             :         revId,
     347             :         serverId);
     348             :   }
     349             : 
     350             :   @Override
     351             :   public String toString() {
     352           0 :     return toStringHelper().toString();
     353             :   }
     354             : 
     355             :   protected ToStringHelper toStringHelper() {
     356           0 :     return MoreObjects.toStringHelper(this)
     357           0 :         .add("key", key)
     358           0 :         .add("lineNbr", lineNbr)
     359           0 :         .add("author", author.getId())
     360           0 :         .add("realAuthor", realAuthor != null ? realAuthor.getId() : "")
     361           0 :         .add("writtenOn", writtenOn)
     362           0 :         .add("side", side)
     363           0 :         .add("message", Objects.toString(message, ""))
     364           0 :         .add("parentUuid", Objects.toString(parentUuid, ""))
     365           0 :         .add("range", Objects.toString(range, ""))
     366           0 :         .add("revId", Objects.toString(revId, ""))
     367           0 :         .add("tag", Objects.toString(tag, ""));
     368             :   }
     369             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750