/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.wisdom.test.assertions;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.primitives.Doubles;
import org.assertj.core.api.AbstractAssert;
import org.wisdom.api.http.MimeTypes;
import org.wisdom.test.http.HttpResponse;
import java.nio.charset.Charset;
/**
* Specific AssertJ Assertion for {@link org.wisdom.test.http.HttpResponse}.
*/
public class HttpResponseAssert<T> extends AbstractAssert<HttpResponseAssert<T>, HttpResponse<T>> {
protected HttpResponseAssert(HttpResponse<T> actual) {
super(actual, HttpResponseAssert.class);
}
/**
* Creates an {@link HttpResponseAssert} instance.
*
* @param actual the HTTP Response
* @param <T> the type of content
* @return the created instance
*/
public static <T> HttpResponseAssert<T> assertThat(HttpResponse<T> actual) {
return new HttpResponseAssert<>(actual);
}
/**
* Checks that the Http Response contains a header named `key` and has the value `value`.
*
* @param key the expected header name
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasHeader(String key, String value) {
isNotNull().hasHeader(key);
if (!value.equals(actual.headers().get(key))) {
failWithMessage("Expected header to contain entry <%s, %s> but value was <%s>", key, value,
String.valueOf(actual.headers().get(key)));
}
return this;
}
/**
* Checks that the Http Response contains a header named `key`.
*
* @param key the expected header name
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasHeader(String key) {
isNotNull();
if (actual.headers().get(key) == null) {
failWithMessage("Expected headers to contain key <%s>", key);
}
return this;
}
/**
* Checks that the Http Response contains a cookie named `cookieName`.
*
* @param cookieName the expected cookie name
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasCookie(String cookieName) {
isNotNull();
if (actual.cookie(cookieName) == null) {
failWithMessage("Expected to contain a cookie with name <%s>", cookieName);
}
return this;
}
/**
* Checks that the Http Response contains a cookie named `cookieName` and has the value `value`.
*
* @param cookieName the expected cookie name
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasCookie(String cookieName, String value) {
isNotNull().hasCookie(cookieName);
if (!actual.cookie(cookieName).getValue().equalsIgnoreCase(value)) {
failWithMessage("Expected to contain a cookie with name <%s> and with value <%s> but the contained value " +
"was <%s>", cookieName, value, actual.cookie(cookieName).getValue());
}
return this;
}
/**
* Checks that the Http Response has the given `content-type`.
*
* @param contentType the expected content type
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasContentType(String contentType) {
isNotNull();
if (!actual.contentType().equals(contentType)) {
failWithMessage("Expected content type to be <%s> but was <%s>", contentType, actual.contentType());
}
return this;
}
/**
* Checks that the Http Response contains the given String in its body. This method works only for String results.
*
* @param inBody expected snippet
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasInBody(String inBody) {
isNotNull();
if (!(actual.body() instanceof String)) {
failWithMessage("Body is not an instance of String, body is <%s>", actual.body().toString());
}
if (!((String) actual.body()).contains(inBody)) {
failWithMessage("Expected body to contain <%s>, but body is <%s>", inBody, actual.body().toString());
}
return this;
}
/**
* Checks that the Http Response does not contains the given String in its body. This method works only for String
* results.
*
* @param inBody expected snippet
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasNotInBody(String inBody) {
isNotNull();
if (!(actual.body() instanceof String)) {
failWithMessage("Body is not an instance of String, body is <%s>", actual.body().toString());
}
if (((String) actual.body()).contains(inBody)) {
failWithMessage("Expected body to NOT contain <%s>, but body is <%s>", inBody, actual.body().toString());
}
return this;
}
/**
* Checks that the Http Response body matches the given regex. This method works only for String results.
*
* @param regex the regex
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> bodyMatches(String regex) {
isNotNull();
if (!(actual.body() instanceof String)) {
failWithMessage("Body is not an instance of String, body is <%s>", actual.body().toString());
}
if (!((String) actual.body()).matches(regex)) {
failWithMessage("Expected body to match <%s>, but body is <%s>", regex, actual.body().toString());
}
return this;
}
/**
* Checks that the Http Response has the given body.
*
* @param body the expected body
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasBody(T body) {
isNotNull();
if (!body.equals(actual.body())) {
failWithMessage("Expected body to be <%s> but was <%s>", body.toString(), actual.body().toString());
}
return this;
}
/**
* Checks that the Http Response body has the given length.
*
* @param length the expected length
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasLength(int length) {
isNotNull();
if (actual.length() != length) {
failWithMessage("Expected length to be <%s> but was <%s>", length, actual.length());
}
return this;
}
/**
* Checks that the Http Response body has the given charset.
*
* @param charset the expected charset
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasCharset(Charset charset) {
isNotNull();
if (!actual.charset().equals(charset.toString())) {
failWithMessage("Expected charset to be <%s> but was <%s>", charset, actual.charset());
}
return this;
}
/**
* Checks that the actual HTTP response has at least one headers.
*
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasHeaders() {
isNotNull();
if (actual.headers().isEmpty()) {
failWithMessage("Expected headers to be not empty");
}
return this;
}
/**
* Checks that the actual HTTP response has a body (content).
*
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasBody() {
isNotNull();
if (actual.body() == null) {
failWithMessage("Expected content to be not null");
}
if (actual.body().toString().length() == 0) {
failWithMessage("Expected content to be not empty");
}
return this;
}
/**
* Checks that the actual HTTP response has the given HTTP Status.
*
* @param status the expected status
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasStatus(int status) {
isNotNull();
if (status != actual.code()) {
failWithMessage("Expected status code to be <%s> but was <%s>", status, actual.code());
}
return this;
}
/**
* Checks that the Http Response contains a textual value at the given Json Pointer (JavaScript Object Notation
* (JSON) Pointer). The Json Pointer syntax is described in the
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* @param path the Json Pointer
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasJsonTextField(String path, String value) {
isNotNull();
isJson();
final JsonNode node = ((JsonNode) actual.body()).at(path);
if (node.isMissingNode()) {
failWithMessage("Expected node pointed by <%s> to be present in <%s>", path, actual.body().toString());
}
if (!node.isTextual()) {
failWithMessage("Expected node pointed by <%s> to be textual", path);
}
if (!node.asText().equals(value)) {
failWithMessage("Expected node pointed by <%s> to be <%s> but was <%s>", path, value, node.asText());
}
return this;
}
/**
* Checks that the Http Response contains a textual value at the given Json Pointer (JavaScript Object Notation
* (JSON) Pointer) containing the given values. The Json Pointer syntax is described in the
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* @param path the Json Pointer
* @param values the expected values
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasJsonTextFieldContaining(String path, String... values) {
isNotNull();
isJson();
final JsonNode node = ((JsonNode) actual.body()).at(path);
if (node.isMissingNode()) {
failWithMessage("Expected node pointed by <%s> to be present in <%s>", path, actual.body().toString());
}
if (!node.isTextual()) {
failWithMessage("Expected node pointed by <%s> to be textual", path);
}
final String s = node.asText();
for (String v : values) {
if (!s.contains(v)) {
failWithMessage("Expected node pointed by <%s> to contain <%s>", path, v);
}
}
return this;
}
/**
* Checks that the Http Response contains a numeric value at the given Json Pointer (JavaScript Object Notation
* (JSON) Pointer). The Json Pointer syntax is described in the
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* @param path the Json Pointer
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasJsonNumericField(String path, int value) {
isNotNull();
isJson();
final JsonNode node = ((JsonNode) actual.body()).at(path);
if (node.isMissingNode()) {
failWithMessage("Expected node pointed by <%s> to be present in <%s>", path, actual.body().toString());
}
if (node.asInt() != value) {
failWithMessage("Expected node pointed by <%s> to be <%s> but was <%s>", path, value, node.asInt());
}
return this;
}
/**
* Checks that the Http Response contains a numeric value at the given Json Pointer (JavaScript Object Notation
* (JSON) Pointer). The Json Pointer syntax is described in the
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* @param path the Json Pointer
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasJsonNumericField(String path, long value) {
isNotNull();
isJson();
final JsonNode node = ((JsonNode) actual.body()).at(path);
if (node.isMissingNode()) {
failWithMessage("Expected node pointed by <%s> to be present in <%s>", path, actual.body().toString());
}
if (node.asLong() != value) {
failWithMessage("Expected node pointed by <%s> to be <%s> but was <%s>", path, value, node.asLong());
}
return this;
}
/**
* Checks that the Http Response contains a numeric value at the given Json Pointer (JavaScript Object Notation
* (JSON) Pointer). The Json Pointer syntax is described in the
* <a href="https://tools.ietf.org/html/rfc6901">RFC 6901</a>.
*
* @param path the Json Pointer
* @param value the expected value
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> hasJsonNumericField(String path, double value) {
isNotNull();
isJson();
final JsonNode node = ((JsonNode) actual.body()).at(path);
if (node.isMissingNode()) {
failWithMessage("Expected node pointed by <%s> to be present in <%s>", path, actual.body().toString());
}
// We cannot compare double directly as it may lead to precision issues.
if (Doubles.compare(node.asDouble(), value) == 0) {
failWithMessage("Expected node pointed by <%s> to be <%s> but was <%s>", path, value, node.asDouble());
}
return this;
}
/**
* Checks that the actual HTTP response has returned a content type that is {@code applicaiton/json}.
*
* @return the current {@link HttpResponseAssert}
*/
public HttpResponseAssert<T> isJson() {
return isNotNull().hasContentType(MimeTypes.JSON);
}
}