| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| MkAnswer |
|
| 1.1176470588235294;1.118 | ||||
| MkAnswer$Simple |
|
| 1.1176470588235294;1.118 |
| 1 | /** | |
| 2 | * Copyright (c) 2011-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.http.mock; | |
| 31 | ||
| 32 | import com.jcabi.aspects.Immutable; | |
| 33 | import com.jcabi.aspects.Loggable; | |
| 34 | import com.jcabi.http.ImmutableHeader; | |
| 35 | import com.jcabi.http.RequestBody; | |
| 36 | import com.jcabi.immutable.Array; | |
| 37 | import com.jcabi.log.Logger; | |
| 38 | import java.net.HttpURLConnection; | |
| 39 | import java.nio.charset.Charset; | |
| 40 | import java.util.LinkedList; | |
| 41 | import java.util.List; | |
| 42 | import java.util.Map; | |
| 43 | import java.util.concurrent.ConcurrentHashMap; | |
| 44 | import java.util.concurrent.ConcurrentMap; | |
| 45 | import lombok.EqualsAndHashCode; | |
| 46 | ||
| 47 | /** | |
| 48 | * Mock response. | |
| 49 | * | |
| 50 | * @author Yegor Bugayenko (yegor@tpc2.com) | |
| 51 | * @version $Id: 92141633cde7f01b091b5dbe21c4d24d37e18837 $ | |
| 52 | * @since 0.10 | |
| 53 | */ | |
| 54 | @Immutable | |
| 55 | @SuppressWarnings("PMD.TooManyMethods") | |
| 56 | public interface MkAnswer { | |
| 57 | ||
| 58 | /** | |
| 59 | * HTTP response status. | |
| 60 | * @return The status code | |
| 61 | */ | |
| 62 | int status(); | |
| 63 | ||
| 64 | /** | |
| 65 | * HTTP response headers. | |
| 66 | * @return The headers | |
| 67 | */ | |
| 68 | Map<String, List<String>> headers(); | |
| 69 | ||
| 70 | /** | |
| 71 | * HTTP response body. | |
| 72 | * @return The body, as a UTF-8 string | |
| 73 | */ | |
| 74 | String body(); | |
| 75 | ||
| 76 | /** | |
| 77 | * HTTP response body as bytes. | |
| 78 | * @return The body, as byte array | |
| 79 | */ | |
| 80 | byte[] bodyBytes(); | |
| 81 | ||
| 82 | /** | |
| 83 | * Simple implementation. | |
| 84 | */ | |
| 85 | @Immutable | |
| 86 | 0 | @EqualsAndHashCode(of = { "code", "hdrs", "content" }) |
| 87 | @Loggable(Loggable.DEBUG) | |
| 88 | final class Simple implements MkAnswer { | |
| 89 | /** | |
| 90 | * The Charset to use. | |
| 91 | */ | |
| 92 | 1 | private static final Charset CHARSET = Charset.forName("UTF-8"); |
| 93 | /** | |
| 94 | * Encapsulated response. | |
| 95 | */ | |
| 96 | private final transient int code; | |
| 97 | /** | |
| 98 | * Headers. | |
| 99 | */ | |
| 100 | private final transient Array<Map.Entry<String, String>> hdrs; | |
| 101 | /** | |
| 102 | * Content received. | |
| 103 | */ | |
| 104 | @Immutable.Array | |
| 105 | private final transient byte[] content; | |
| 106 | /** | |
| 107 | * Public ctor. | |
| 108 | * @param body Body of HTTP response | |
| 109 | */ | |
| 110 | public Simple(final String body) { | |
| 111 | 75 | this(HttpURLConnection.HTTP_OK, body); |
| 112 | 75 | } |
| 113 | /** | |
| 114 | * Public ctor (with empty HTTP body). | |
| 115 | * @param status HTTP status | |
| 116 | * @since 1.9 | |
| 117 | */ | |
| 118 | public Simple(final int status) { | |
| 119 | 9 | this(status, ""); |
| 120 | 9 | } |
| 121 | /** | |
| 122 | * Public ctor. | |
| 123 | * @param status HTTP status | |
| 124 | * @param body Body of HTTP response | |
| 125 | */ | |
| 126 | public Simple(final int status, final String body) { | |
| 127 | 92 | this( |
| 128 | status, new Array<Map.Entry<String, String>>(), | |
| 129 | body.getBytes(MkAnswer.Simple.CHARSET) | |
| 130 | ); | |
| 131 | 92 | } |
| 132 | /** | |
| 133 | * Public ctor. | |
| 134 | * @param status HTTP status | |
| 135 | * @param headers HTTP headers | |
| 136 | * @param body Body of HTTP response | |
| 137 | */ | |
| 138 | public Simple(final int status, | |
| 139 | final Iterable<Map.Entry<String, String>> headers, | |
| 140 | 124 | final byte[] body) { |
| 141 | 124 | this.code = status; |
| 142 | 124 | this.hdrs = new Array<Map.Entry<String, String>>(headers); |
| 143 | 124 | this.content = body.clone(); |
| 144 | 124 | } |
| 145 | @Override | |
| 146 | public int status() { | |
| 147 | 107 | return this.code; |
| 148 | } | |
| 149 | @Override | |
| 150 | @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") | |
| 151 | public Map<String, List<String>> headers() { | |
| 152 | 134 | final ConcurrentMap<String, List<String>> map = |
| 153 | new ConcurrentHashMap<>(0); | |
| 154 | 133 | for (final Map.Entry<String, String> header : this.hdrs) { |
| 155 | 66 | map.putIfAbsent(header.getKey(), new LinkedList<String>()); |
| 156 | 66 | map.get(header.getKey()).add(header.getValue()); |
| 157 | 66 | } |
| 158 | 133 | return map; |
| 159 | } | |
| 160 | @Override | |
| 161 | public String body() { | |
| 162 | 4 | return new String(this.content, MkAnswer.Simple.CHARSET); |
| 163 | } | |
| 164 | @Override | |
| 165 | public byte[] bodyBytes() { | |
| 166 | 107 | return this.content.clone(); |
| 167 | } | |
| 168 | @Override | |
| 169 | public String toString() { | |
| 170 | 0 | final StringBuilder text = new StringBuilder(0) |
| 171 | .append(this.code).append('\n'); | |
| 172 | 0 | for (final Map.Entry<String, String> header : this.hdrs) { |
| 173 | 0 | text.append( |
| 174 | Logger.format( | |
| 175 | "%s: %s\n", | |
| 176 | header.getKey(), | |
| 177 | header.getValue() | |
| 178 | ) | |
| 179 | ); | |
| 180 | 0 | } |
| 181 | 0 | return text.append('\n') |
| 182 | .append(new RequestBody.Printable(this.content)) | |
| 183 | .toString(); | |
| 184 | } | |
| 185 | /** | |
| 186 | * Make a copy of this answer, with an extra header. | |
| 187 | * @param name Name of the header | |
| 188 | * @param value ImmutableHeader value | |
| 189 | * @return New answer | |
| 190 | */ | |
| 191 | public MkAnswer.Simple withHeader(final String name, | |
| 192 | final String value) { | |
| 193 | 21 | return new MkAnswer.Simple( |
| 194 | this.code, | |
| 195 | this.hdrs.with(new ImmutableHeader(name, value)), | |
| 196 | this.content | |
| 197 | ); | |
| 198 | } | |
| 199 | /** | |
| 200 | * Make a copy of this answer, with another status code. | |
| 201 | * @param status Status code | |
| 202 | * @return New answer | |
| 203 | */ | |
| 204 | public MkAnswer.Simple withStatus(final int status) { | |
| 205 | 3 | return new MkAnswer.Simple( |
| 206 | status, | |
| 207 | this.hdrs, | |
| 208 | this.content | |
| 209 | ); | |
| 210 | } | |
| 211 | /** | |
| 212 | * Make a copy of this answer, with another body. | |
| 213 | * @param body Body | |
| 214 | * @return New answer | |
| 215 | */ | |
| 216 | public MkAnswer.Simple withBody(final String body) { | |
| 217 | 0 | return new MkAnswer.Simple( |
| 218 | this.code, | |
| 219 | this.hdrs, | |
| 220 | body.getBytes(MkAnswer.Simple.CHARSET) | |
| 221 | ); | |
| 222 | } | |
| 223 | /** | |
| 224 | * Make a copy of this answer, with another body. | |
| 225 | * @param body Body | |
| 226 | * @return New answer | |
| 227 | */ | |
| 228 | public MkAnswer.Simple withBody(final byte[] body) { | |
| 229 | 1 | return new MkAnswer.Simple(this.code, this.hdrs, body); |
| 230 | } | |
| 231 | } | |
| 232 | ||
| 233 | } |