View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2013-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.jcabi.github;
6   
7   import com.jcabi.http.request.FakeRequest;
8   import jakarta.json.Json;
9   import jakarta.json.JsonObject;
10  import java.io.IOException;
11  import java.util.ArrayList;
12  import org.hamcrest.MatcherAssert;
13  import org.hamcrest.Matchers;
14  import org.junit.jupiter.api.Assertions;
15  import org.junit.jupiter.api.Test;
16  import org.mockito.ArgumentMatchers;
17  import org.mockito.Mockito;
18  
19  /**
20   * Test case for {@link Issue}.
21   * @since 0.1
22   * @checkstyle MultipleStringLiterals (500 lines)
23   */
24  @SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods"})
25  final class IssueTest {
26  
27      @Test
28      void fetchesProperties() throws IOException {
29          final Issue issue = Mockito.mock(Issue.class);
30          Mockito.doReturn(
31              Json.createObjectBuilder()
32                  .add("title", "this is some text \u20ac")
33                  .add("body", "body of the issue")
34                  .build()
35          ).when(issue).json();
36          final Issue.Smart smart = new Issue.Smart(issue);
37          MatcherAssert.assertThat(
38              "Value is null",
39              smart.title(),
40              Matchers.notNullValue()
41          );
42          MatcherAssert.assertThat(
43              "Value is null",
44              smart.body(),
45              Matchers.notNullValue()
46          );
47      }
48  
49      @Test
50      void detectsPullRequest() throws IOException {
51          final Issue issue = Mockito.mock(Issue.class);
52          Mockito.doReturn(
53              Json.createObjectBuilder().add(
54                  "pull_request",
55                  Json.createObjectBuilder().add(
56                      "html_url", "http://ibm.com/pulls/3"
57                  )
58              ).build()
59          ).when(issue).json();
60          final Pulls pulls = Mockito.mock(Pulls.class);
61          final Repo repo = Mockito.mock(Repo.class);
62          final Pull pull = Mockito.mock(Pull.class);
63          Mockito.doReturn(repo).when(issue).repo();
64          Mockito.doReturn(pulls).when(repo).pulls();
65          Mockito.when(pulls.get(ArgumentMatchers.eq(3))).thenReturn(pull);
66          MatcherAssert.assertThat(
67              "Values are not equal",
68              new Issue.Smart(issue).isPull(),
69              Matchers.is(true)
70          );
71          new Issue.Smart(issue).pull();
72          Mockito.verify(pulls).get(3);
73      }
74  
75      @Test
76      void detectsPullRequestAbsence() throws IOException {
77          final Issue issue = Mockito.mock(Issue.class);
78          Mockito.doReturn(
79              Json.createObjectBuilder().add(
80                  "pull_request",
81                  Json.createObjectBuilder().addNull("html_url")
82              ).build()
83          ).when(issue).json();
84          MatcherAssert.assertThat(
85              "Values are not equal",
86              new Issue.Smart(issue).isPull(),
87              Matchers.is(false)
88          );
89      }
90  
91      @Test
92      void detectsFullPullRequestAbsence() throws IOException {
93          final Issue issue = Mockito.mock(Issue.class);
94          Mockito.doReturn(
95              Json.createObjectBuilder().build()
96          ).when(issue).json();
97          MatcherAssert.assertThat(
98              "Values are not equal",
99              new Issue.Smart(issue).isPull(),
100             Matchers.is(false)
101         );
102     }
103 
104     /**
105      * Issue.Smart can fetch issue's labels in read-only mode.
106      * @throws IOException If some problem inside.
107      */
108     @Test
109     void fetchLabelsRO() throws IOException {
110         final String name = "bug";
111         final JsonObject json = Json.createObjectBuilder().add(
112             "labels",
113             Json.createArrayBuilder().add(
114                 Json.createObjectBuilder()
115                     .add("name", name)
116                     .add("color", "f29513")
117             )
118         ).build();
119         final Issue issue = new RtIssue(
120             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
121         );
122         final IssueLabels labels = new Issue.Smart(issue).roLabels();
123         final Label label = labels.iterate().iterator().next();
124         MatcherAssert.assertThat(
125             "Value is null", label, Matchers.notNullValue()
126         );
127     }
128 
129     /**
130      * Issue.Smart read-only labels cannot add labels.
131      * @throws IOException If some problem inside.
132      */
133     @Test
134     void roLabelsCannotAdd() throws IOException {
135         final JsonObject json = Json.createObjectBuilder().add(
136             "labels",
137             Json.createArrayBuilder().add(
138                 Json.createObjectBuilder()
139                     .add("name", "bug")
140                     .add("color", "f29513")
141             )
142         ).build();
143         final Issue issue = new RtIssue(
144             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
145         );
146         final IssueLabels labels = new Issue.Smart(issue).roLabels();
147         Assertions.assertThrows(
148             UnsupportedOperationException.class,
149             () -> labels.add(new ArrayList<>(0)),
150             "Read-only labels cannot be modified"
151         );
152     }
153 
154     /**
155      * Issue.Smart read-only labels cannot replace labels.
156      * @throws IOException If some problem inside.
157      */
158     @Test
159     void roLabelsCannotReplace() throws IOException {
160         final JsonObject json = Json.createObjectBuilder().add(
161             "labels",
162             Json.createArrayBuilder().add(
163                 Json.createObjectBuilder()
164                     .add("name", "bug")
165                     .add("color", "f29513")
166             )
167         ).build();
168         final Issue issue = new RtIssue(
169             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
170         );
171         final IssueLabels labels = new Issue.Smart(issue).roLabels();
172         Assertions.assertThrows(
173             UnsupportedOperationException.class,
174             () -> labels.replace(new ArrayList<>(0)),
175             "Read-only labels cannot be modified"
176         );
177     }
178 
179     /**
180      * Issue.Smart read-only labels cannot remove labels.
181      * @throws IOException If some problem inside.
182      */
183     @Test
184     void roLabelsCannotRemove() throws IOException {
185         final JsonObject json = Json.createObjectBuilder().add(
186             "labels",
187             Json.createArrayBuilder().add(
188                 Json.createObjectBuilder()
189                     .add("name", "bug")
190                     .add("color", "f29513")
191             )
192         ).build();
193         final Issue issue = new RtIssue(
194             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
195         );
196         final IssueLabels labels = new Issue.Smart(issue).roLabels();
197         Assertions.assertThrows(
198             UnsupportedOperationException.class,
199             () -> labels.remove("bug"),
200             "Read-only labels cannot be modified"
201         );
202     }
203 
204     /**
205      * Issue.Smart read-only labels cannot clear labels.
206      * @throws IOException If some problem inside.
207      */
208     @Test
209     void roLabelsCannotClear() throws IOException {
210         final JsonObject json = Json.createObjectBuilder().add(
211             "labels",
212             Json.createArrayBuilder().add(
213                 Json.createObjectBuilder()
214                     .add("name", "bug")
215                     .add("color", "f29513")
216             )
217         ).build();
218         final Issue issue = new RtIssue(
219             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
220         );
221         final IssueLabels labels = new Issue.Smart(issue).roLabels();
222         Assertions.assertThrows(
223             UnsupportedOperationException.class,
224             () -> labels.clear(),
225             "Read-only labels cannot be modified"
226         );
227     }
228 
229     /**
230      * Issue.Smart read-only label cannot be patched.
231      * @throws IOException If some problem inside.
232      */
233     @Test
234     void roLabelCannotBePatchedTest() throws IOException {
235         final JsonObject json = Json.createObjectBuilder().add(
236             "labels",
237             Json.createArrayBuilder().add(
238                 Json.createObjectBuilder()
239                     .add("name", "bug")
240                     .add("color", "f29513")
241             )
242         ).build();
243         final Issue issue = new RtIssue(
244             new FakeRequest().withBody(json.toString()), IssueTest.repo(), 1
245         );
246         final IssueLabels labels = new Issue.Smart(issue).roLabels();
247         final Label label = labels.iterate().iterator().next();
248         Assertions.assertThrows(
249             UnsupportedOperationException.class,
250             () -> label.patch(Mockito.mock(JsonObject.class)),
251             "Read-only label cannot be modified"
252         );
253     }
254 
255     /**
256      * Mock repo for GhIssue creation.
257      * @return The mock repo.
258      */
259     private static Repo repo() {
260         final Repo repo = Mockito.mock(Repo.class);
261         final Coordinates coords = Mockito.mock(Coordinates.class);
262         Mockito.doReturn(coords).when(repo).coordinates();
263         Mockito.doReturn("user").when(coords).user();
264         Mockito.doReturn("repo").when(coords).repo();
265         return repo;
266     }
267 }