Coverage Report - com.jcabi.github.mock.MkIssue
 
Classes in this File Line Coverage Branch Coverage Complexity
MkIssue
91%
63/69
30%
13/42
1.786
MkIssue$AjcClosure1
100%
1/1
N/A
1.786
MkIssue$AjcClosure11
100%
1/1
N/A
1.786
MkIssue$AjcClosure13
100%
1/1
N/A
1.786
MkIssue$AjcClosure15
100%
1/1
N/A
1.786
MkIssue$AjcClosure17
100%
1/1
N/A
1.786
MkIssue$AjcClosure3
100%
1/1
N/A
1.786
MkIssue$AjcClosure5
100%
1/1
N/A
1.786
MkIssue$AjcClosure7
100%
1/1
N/A
1.786
MkIssue$AjcClosure9
100%
1/1
N/A
1.786
MkIssue$MkIssueEventMapping
100%
9/9
N/A
1.786
 
 1  4
 /**
 2  
  * Copyright (c) 2013-2017, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.github.mock;
 31  
 
 32  
 import com.google.common.base.Optional;
 33  
 import com.jcabi.aspects.Immutable;
 34  
 import com.jcabi.aspects.Loggable;
 35  
 import com.jcabi.github.Comments;
 36  
 import com.jcabi.github.Coordinates;
 37  
 import com.jcabi.github.Event;
 38  
 import com.jcabi.github.Issue;
 39  
 import com.jcabi.github.IssueLabels;
 40  
 import com.jcabi.github.Label;
 41  
 import com.jcabi.github.Repo;
 42  
 import com.jcabi.xml.XML;
 43  
 import java.io.IOException;
 44  
 import java.util.Map;
 45  
 import javax.json.Json;
 46  
 import javax.json.JsonArrayBuilder;
 47  
 import javax.json.JsonObject;
 48  
 import javax.json.JsonObjectBuilder;
 49  
 import javax.json.JsonValue;
 50  
 import lombok.EqualsAndHashCode;
 51  
 
 52  
 /**
 53  
  * Mock Github issue.
 54  
  *
 55  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 56  
  * @version $Id: a27946c55d6f51aa6f93db3d2b27427be192a443 $
 57  
  * @since 0.5
 58  
  * @checkstyle ClassDataAbstractionCoupling (500 lines)
 59  
  */
 60  0
 @Immutable
 61  
 @Loggable(Loggable.DEBUG)
 62  1
 @EqualsAndHashCode(of = { "storage", "self", "coords", "num" })
 63  
 @SuppressWarnings("PMD.TooManyMethods")
 64  24
 final class MkIssue implements Issue {
 65  
 
 66  
     /**
 67  
      * Storage.
 68  
      */
 69  
     private final transient MkStorage storage;
 70  
 
 71  
     /**
 72  
      * Login of the user logged in.
 73  
      */
 74  
     private final transient String self;
 75  
 
 76  
     /**
 77  
      * Repo name.
 78  
      */
 79  
     private final transient Coordinates coords;
 80  
 
 81  
     /**
 82  
      * Issue number.
 83  
      */
 84  
     private final transient int num;
 85  
 
 86  
     /**
 87  
      * Public ctor.
 88  
      * @param stg Storage
 89  
      * @param login User to login
 90  
      * @param rep Repo
 91  
      * @param number Issue number
 92  
      * @checkstyle ParameterNumber (5 lines)
 93  
      */
 94  
     MkIssue(
 95  
         final MkStorage stg,
 96  
         final String login,
 97  
         final Coordinates rep,
 98  
         final int number
 99  284
     ) {
 100  284
         this.storage = stg;
 101  284
         this.self = login;
 102  284
         this.coords = rep;
 103  284
         this.num = number;
 104  284
     }
 105  
 
 106  
     @Override
 107  
     public String toString() {
 108  0
         return Integer.toString(this.num);
 109  
     }
 110  
 
 111  
     @Override
 112  
     public Repo repo() {
 113  38
         return new MkRepo(this.storage, this.self, this.coords);
 114  
     }
 115  
 
 116  
     @Override
 117  
     public int number() {
 118  64
         return this.num;
 119  
     }
 120  
 
 121  
     @Override
 122  
     public Comments comments() {
 123  
         try {
 124  12
             return new MkComments(
 125  
                 this.storage, this.self, this.coords, this.num
 126  
             );
 127  0
         } catch (final IOException ex) {
 128  0
             throw new IllegalStateException(ex);
 129  
         }
 130  
     }
 131  
 
 132  
     @Override
 133  
     public IssueLabels labels() {
 134  
         try {
 135  84
             return new MkIssueLabels(
 136  
                 this.storage, this.self, this.coords, this.num
 137  
             );
 138  0
         } catch (final IOException ex) {
 139  0
             throw new IllegalStateException(ex);
 140  
         }
 141  
     }
 142  
 
 143  
     @Override
 144  
     public Iterable<Event> events() throws IOException {
 145  24
         return new MkIterable<Event>(
 146  
             this.storage,
 147  8
             String.format(
 148  
                 // @checkstyle LineLength (1 line)
 149  
                 "/github/repos/repo[@coords='%s']/issue-events/issue-event[issue='%s']",
 150  
                 this.coords,
 151  8
                 this.num
 152  
             ),
 153  
             new MkIssueEventMapping(this)
 154  
         );
 155  
     }
 156  
 
 157  
     @Override
 158  
     public boolean exists() throws IOException {
 159  8
         return this.storage.xml().xpath(
 160  2
             String.format("%s/number/text()", this.xpath())
 161  2
         ).size() == 1;
 162  
     }
 163  
 
 164  
     @Override
 165  
     public int compareTo(
 166  
         final Issue issue
 167  
     ) {
 168  4
         return this.number() - issue.number();
 169  
     }
 170  
 
 171  
     @Override
 172  
     public void patch(
 173  
         final JsonObject json
 174  
     ) throws IOException {
 175  14
         final Issue.Smart smart = new Issue.Smart(this);
 176  7
         final boolean was = smart.isOpen();
 177  7
         new JsonPatch(this.storage).patch(this.xpath(), json);
 178  7
         final boolean now = smart.isOpen();
 179  7
         if (now != was) {
 180  
             final String type;
 181  4
             if (now) {
 182  1
                 type = Event.REOPENED;
 183  
             } else {
 184  3
                 type = Event.CLOSED;
 185  
             }
 186  4
             new MkIssueEvents(this.storage, this.self, this.coords)
 187  4
                 .create(type, this.num, this.self, Optional.<String>absent());
 188  
         }
 189  7
     }
 190  
 
 191  
     @Override
 192  
     public JsonObject json() throws IOException {
 193  64
         final XML xml = this.storage.xml();
 194  32
         final JsonObject obj = new JsonNode(
 195  32
             xml.nodes(this.xpath()).get(0)
 196  32
         ).json();
 197  32
         final JsonObjectBuilder json = Json.createObjectBuilder();
 198  32
         for (final Map.Entry<String, JsonValue> val: obj.entrySet()) {
 199  310
             json.add(val.getKey(), val.getValue());
 200  310
         }
 201  32
         final JsonArrayBuilder array = Json.createArrayBuilder();
 202  32
         for (final Label label : this.labels().iterate()) {
 203  2
             array.add(
 204  1
                 Json.createObjectBuilder().add("name", label.name()).build()
 205  
             );
 206  1
         }
 207  32
         final JsonObjectBuilder res = json
 208  32
             .add("labels", array)
 209  32
             .add(
 210  
                 // @checkstyle MultipleStringLiteralsCheck (1 line)
 211  
                 "assignee",
 212  64
                 Json.createObjectBuilder().add(
 213  32
                     "login", obj.getString("assignee", "")
 214  32
                 ).build()
 215  
             );
 216  32
         final JsonObjectBuilder pull = Json.createObjectBuilder();
 217  32
         final String html = "html_url";
 218  64
         if (xml.nodes(
 219  32
                 String.format(
 220  
                     // @checkstyle LineLengthCheck (1 line)
 221  
                     "/github/repos/repo[@coords='%s']/pulls/pull/number[text() = '%d']",
 222  
                     this.coords,
 223  32
                     this.num
 224  
                 )
 225  32
             ).isEmpty()) {
 226  29
             pull.addNull(html);
 227  
         } else {
 228  6
             pull.add(
 229  
                 html,
 230  3
                 String.format(
 231  
                     "https://%s/pulls/%d",
 232  
                     this.coords,
 233  3
                     this.num
 234  
                 )
 235  
             );
 236  
         }
 237  32
         return res.add("pull_request", pull.build()).build();
 238  
     }
 239  
 
 240  
     /**
 241  
      * XPath of this element in XML tree.
 242  
      * @return XPath
 243  
      */
 244  
     private String xpath() {
 245  82
         return String.format(
 246  
             "/github/repos/repo[@coords='%s']/issues/issue[number='%d']",
 247  41
             this.coords, this.num
 248  
         );
 249  
     }
 250  
 
 251  12
     private static class MkIssueEventMapping
 252  
         implements MkIterable.Mapping<Event> {
 253  
         /**
 254  
          * Issue events.
 255  
          */
 256  
         private final transient MkIssueEvents evts;
 257  
 
 258  
         /**
 259  
          * Constructor.
 260  
          * @param issue Mock issue to get events from
 261  
          * @throws IOException If there is any I/O problem
 262  
          */
 263  
         public MkIssueEventMapping(
 264  
             final MkIssue issue
 265  8
         ) throws IOException {
 266  8
             this.evts = new MkIssueEvents(
 267  8
                 issue.storage,
 268  8
                 issue.self,
 269  8
                 issue.coords
 270  
             );
 271  8
         }
 272  
 
 273  
         @Override
 274  
         public Event map(
 275  
             final XML xml
 276  
         ) {
 277  24
             return this.evts.get(
 278  12
                 Integer.parseInt(xml.xpath("number/text()").get(0))
 279  
             );
 280  
         }
 281  
     }
 282  
 }