View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.jcabi.http.request;
6   
7   import com.jcabi.http.Request;
8   import com.jcabi.http.Wire;
9   import com.jcabi.http.mock.MkAnswer;
10  import com.jcabi.http.mock.MkContainer;
11  import com.jcabi.http.mock.MkGrizzlyContainer;
12  import com.jcabi.immutable.ArrayMap;
13  import jakarta.json.Json;
14  import jakarta.ws.rs.core.HttpHeaders;
15  import jakarta.ws.rs.core.MediaType;
16  import java.io.IOException;
17  import org.hamcrest.MatcherAssert;
18  import org.hamcrest.Matchers;
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  import org.mockito.Mockito;
22  
23  /**
24   * Test case for {@link BaseRequest}.
25   *
26   * @since 1.0
27   */
28  final class BaseRequestTest {
29  
30      /**
31       * Property name of Exception.
32       */
33      private static final String MESSAGE = "message";
34  
35      /**
36       * BaseRequest can build the right destination URI.
37       */
38      @Test
39      void buildsDestinationUri() {
40          final Wire wire = Mockito.mock(Wire.class);
41          MatcherAssert.assertThat(
42              "should has the right destination URI",
43              new BaseRequest(wire, "http://localhost:88/t/f")
44                  .uri().path("/bar").queryParam("u1", "\u20ac")
45                  .queryParams(new ArrayMap<String, String>().with("u2", ""))
46                  .userInfo("hey:\u20ac").back().uri().get(),
47              Matchers.hasToString(
48                  "http://hey:%E2%82%AC@localhost:88/t/f/bar?u1=%E2%82%AC&u2="
49              )
50          );
51      }
52  
53      /**
54       * BaseRequest can set body to JSON.
55       */
56      @Test
57      void printsJsonInBody() {
58          final Wire wire = Mockito.mock(Wire.class);
59          MatcherAssert.assertThat(
60              "should equals to '{\"foo\":\"test 1\"}'",
61              new BaseRequest(wire, "http://localhost:88/x").body().set(
62                  Json.createObjectBuilder().add("foo", "test 1").build()
63              ).get(),
64              Matchers.equalTo("{\"foo\":\"test 1\"}")
65          );
66      }
67  
68      /**
69       * BaseRequest can include the port number.
70       */
71      @Test
72      void includesPort() {
73          final Wire wire = Mockito.mock(Wire.class);
74          MatcherAssert.assertThat(
75              "should has 'http://localhost:8080/'",
76              // @checkstyle MagicNumber (2 lines)
77              new BaseRequest(wire, "http://localhost")
78                  .uri().port(8080).back().uri().get(),
79              Matchers.hasToString("http://localhost:8080/")
80          );
81      }
82  
83      /**
84       * FakeRequest can identify itself uniquely.
85       */
86      @Test
87      void identifiesUniquely() {
88          final Wire wire = Mockito.mock(Wire.class);
89          MatcherAssert.assertThat(
90              "should not equals",
91              new BaseRequest(wire, "").header("header-1", "value-1"),
92              Matchers.not(
93                  Matchers.equalTo(
94                      new BaseRequest(wire, "").header("header-2", "value-2")
95                  )
96              )
97          );
98          MatcherAssert.assertThat(
99              "should equals",
100             new BaseRequest(wire, ""),
101             Matchers.equalTo(new BaseRequest(wire, ""))
102         );
103     }
104 
105     /**
106      * Throws exception when using formParam on multipart-body without
107      * content-type defined.
108      */
109     @Test
110     void exceptionWhenMissingContentType() {
111         final Wire wire = Mockito.mock(Wire.class);
112         MatcherAssert.assertThat(
113             "should be error when multipart-body without content-type",
114             Assertions.assertThrows(
115                 IllegalStateException.class,
116                 () -> new BaseRequest(wire, "")
117                     .multipartBody()
118                     .formParam("a", "value")
119                     .back()
120             ),
121             Matchers.hasProperty(
122                 BaseRequestTest.MESSAGE,
123                 Matchers.is(BaseRequestTest.boundaryErrorMesg())
124             )
125         );
126     }
127 
128     /**
129      * Throws exception when using formParam on multipartbody without boundary
130      * provided in content-type defined.
131      */
132     @Test
133     void exceptionWhenMissingBoundary() {
134         final Wire wire = Mockito.mock(Wire.class);
135         MatcherAssert.assertThat(
136             "should be error when multipart-body without content-type",
137             Assertions.assertThrows(
138                 IllegalStateException.class,
139                 () -> new BaseRequest(wire, "")
140                     .header(
141                         HttpHeaders.CONTENT_TYPE,
142                         MediaType.MULTIPART_FORM_DATA
143                     )
144                     .multipartBody().formParam("b", "val").back()
145             ),
146             Matchers.hasProperty(
147                 BaseRequestTest.MESSAGE,
148                 Matchers.is(BaseRequestTest.boundaryErrorMesg())
149             )
150         );
151     }
152 
153     @Test
154     void shouldHaveCorrectFormParameters() throws IOException {
155         final MkContainer srv = new MkGrizzlyContainer()
156             .next(new MkAnswer.Simple("OK")).start();
157         new JdkRequest(srv.home())
158             .body()
159             .formParam("foo1", "bar1")
160             .back()
161             .body()
162             .formParam("foo2", "bar2")
163             .back()
164             .body()
165             .formParam("foo3", "bar3")
166             .formParam("foo4", "bar4")
167             .back()
168             .method(Request.POST)
169             .fetch();
170         MatcherAssert.assertThat(
171             "should be match to 'foo1=bar1&foo2=bar2&foo3=bar3&foo4=bar4'",
172             srv.take().body(),
173             Matchers.is("foo1=bar1&foo2=bar2&foo3=bar3&foo4=bar4")
174         );
175     }
176 
177     /**
178      * Boundary error message.
179      *
180      * @return Message error as String.
181      */
182     private static String boundaryErrorMesg() {
183         return "Content-Type: multipart/form-data requires boundary";
184     }
185 }