/* * Copyright 2012-2017 the original author or authors. * * 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. */ package org.springframework.boot.test.json; import java.io.File; import java.io.InputStream; import java.nio.charset.Charset; import java.util.List; import java.util.Map; import com.jayway.jsonpath.JsonPath; import org.assertj.core.api.AbstractAssert; import org.assertj.core.api.AbstractBooleanAssert; import org.assertj.core.api.AbstractCharSequenceAssert; import org.assertj.core.api.AbstractListAssert; import org.assertj.core.api.AbstractMapAssert; import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.Assert; import org.assertj.core.api.Assertions; import org.assertj.core.api.ObjectAssert; import org.skyscreamer.jsonassert.JSONCompare; import org.skyscreamer.jsonassert.JSONCompareMode; import org.skyscreamer.jsonassert.JSONCompareResult; import org.skyscreamer.jsonassert.comparator.JSONComparator; import org.springframework.core.io.Resource; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * AssertJ {@link Assert} for {@link JsonContent}. * * @author Phillip Webb * @author Andy Wilkinson * @since 1.4.0 */ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSequence> { private final JsonLoader loader; /** * Create a new {@link JsonContentAssert} instance that will load resources as UTF-8. * @param resourceLoadClass the source class used to load resources * @param json the actual JSON content */ public JsonContentAssert(Class<?> resourceLoadClass, CharSequence json) { this(resourceLoadClass, null, json); } /** * Create a new {@link JsonContentAssert} instance that will load resources in the * given {@code charset}. * @param resourceLoadClass the source class used to load resources * @param charset the charset of the JSON resources * @param json the actual JSON content * @since 1.4.1 */ public JsonContentAssert(Class<?> resourceLoadClass, Charset charset, CharSequence json) { super(json, JsonContentAssert.class); this.loader = new JsonLoader(resourceLoadClass, charset); } /** * Overridden version of {@code isEqualTo} to perform JSON tests based on the object * type. * @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object) */ @Override public JsonContentAssert isEqualTo(Object expected) { if (expected == null || expected instanceof CharSequence) { return isEqualToJson((CharSequence) expected); } if (expected instanceof byte[]) { return isEqualToJson((byte[]) expected); } if (expected instanceof File) { return isEqualToJson((File) expected); } if (expected instanceof InputStream) { return isEqualToJson((InputStream) expected); } if (expected instanceof Resource) { return isEqualToJson((Resource) expected); } throw new AssertionError("Unsupport type for JSON assert " + expected.getClass()); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON. The {@code expected} value can contain the JSON itself or, * if it ends with {@code .json}, the name of a resource to be loaded using * {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(CharSequence expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON bytes. * @param expected the expected JSON bytes * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(byte[] expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON file. * @param expected a file containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(File expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(InputStream expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal * to the specified JSON resource. * @param expected a resource containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(Resource expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON. The {@code expected} value can contain the JSON itself or, if * it ends with {@code .json}, the name of a resource to be loaded using * {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(CharSequence expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(String path, Class<?> resourceLoadClass) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON bytes. * @param expected the expected JSON bytes * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(byte[] expected) { return assertNotFailed( compare(this.loader.getJson(expected), JSONCompareMode.STRICT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON file. * @param expected a file containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(File expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON input stream. * @param expected an input stream containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(InputStream expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to * the specified JSON resource. * @param expected a resource containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isStrictlyEqualToJson(Resource expected) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is equal to the specified JSON. The {@code expected} * value can contain the JSON itself or, if it ends with {@code .json}, the name of a * resource to be loaded using {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(CharSequence expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is equal to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotFailed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is equal to the specified JSON bytes. * @param expected the expected JSON bytes * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(byte[] expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is equal to the specified JSON file. * @param expected a file containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(File expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is equal to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(InputStream expected, JSONCompareMode compareMode) { return assertNotFailed(compare(this.loader.getJson(expected), compareMode)); } /** * Verifies that the actual value is equal to the specified JSON resource. * @param expected a resource containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(Resource expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is equal to the specified JSON. The {@code expected} * value can contain the JSON itself or, if it ends with {@code .json}, the name of a * resource to be loaded using {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(CharSequence expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is equal to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass, JSONComparator comparator) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotFailed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is equal to the specified JSON bytes. * @param expected the expected JSON bytes * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(byte[] expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is equal to the specified JSON file. * @param expected a file containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(File expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is equal to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(InputStream expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is equal to the specified JSON resource. * @param expected a resource containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is not equal to the given one */ public JsonContentAssert isEqualToJson(Resource expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotFailed(compare(expectedJson, comparator)); } /** * Overridden version of {@code isNotEqualTo} to perform JSON tests based on the * object type. * @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object) */ @Override public JsonContentAssert isNotEqualTo(Object expected) { if (expected == null || expected instanceof CharSequence) { return isNotEqualToJson((CharSequence) expected); } if (expected instanceof byte[]) { return isNotEqualToJson((byte[]) expected); } if (expected instanceof File) { return isNotEqualToJson((File) expected); } if (expected instanceof InputStream) { return isNotEqualToJson((InputStream) expected); } if (expected instanceof Resource) { return isNotEqualToJson((Resource) expected); } throw new AssertionError("Unsupport type for JSON assert " + expected.getClass()); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON. The {@code expected} value can contain the JSON itself * or, if it ends with {@code .json}, the name of a resource to be loaded using * {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(CharSequence expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON bytes. * @param expected the expected JSON bytes * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(byte[] expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON file. * @param expected a file containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(File expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(InputStream expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently} * equal to the specified JSON resource. * @param expected a resource containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(Resource expected) { return assertNotPassed( compare(this.loader.getJson(expected), JSONCompareMode.LENIENT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON. The {@code expected} value can contain the JSON itself or, * if it ends with {@code .json}, the name of a resource to be loaded using * {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(CharSequence expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(String path, Class<?> resourceLoadClass) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON bytes. * @param expected the expected JSON bytes * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(byte[] expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON file. * @param expected a file containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(File expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(InputStream expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal * to the specified JSON resource. * @param expected a resource containing the expected JSON * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotStrictlyEqualToJson(Resource expected) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT)); } /** * Verifies that the actual value is not equal to the specified JSON. The * {@code expected} value can contain the JSON itself or, if it ends with * {@code .json}, the name of a resource to be loaded using {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(CharSequence expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON bytes. * @param expected the expected JSON bytes * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(byte[] expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON file. * @param expected a file containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(File expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(InputStream expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON resource. * @param expected a resource containing the expected JSON * @param compareMode the compare mode used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(Resource expected, JSONCompareMode compareMode) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, compareMode)); } /** * Verifies that the actual value is not equal to the specified JSON. The * {@code expected} value can contain the JSON itself or, if it ends with * {@code .json}, the name of a resource to be loaded using {@code resourceLoadClass}. * @param expected the expected JSON or the name of a resource containing the expected * JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(CharSequence expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is not equal to the specified JSON resource. * @param path the name of a resource containing the expected JSON * @param resourceLoadClass the source class used to load the resource * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass, JSONComparator comparator) { String expectedJson = this.loader.getJson(path, resourceLoadClass); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is not equal to the specified JSON bytes. * @param expected the expected JSON bytes * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(byte[] expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is not equal to the specified JSON file. * @param expected a file containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(File expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is not equal to the specified JSON input stream. * @param expected an input stream containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(InputStream expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verifies that the actual value is not equal to the specified JSON resource. * @param expected a resource containing the expected JSON * @param comparator the comparator used when checking * @return {@code this} assertion object * @throws AssertionError if the actual JSON value is equal to the given one */ public JsonContentAssert isNotEqualToJson(Resource expected, JSONComparator comparator) { String expectedJson = this.loader.getJson(expected); return assertNotPassed(compare(expectedJson, comparator)); } /** * Verify that the actual value at the given JSON path produces a non-null result. If * the JSON path expression is not {@linkplain JsonPath#isDefinite() definite}, this * method verifies that the value at the given path is not <em>empty</em>. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing */ public JsonContentAssert hasJsonPathValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(Object.class, "an object"); return this; } /** * Verify that the actual value at the given JSON path produces a non-null string * result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing or not a string */ public JsonContentAssert hasJsonPathStringValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(String.class, "a string"); return this; } /** * Verify that the actual value at the given JSON path produces a non-null number * result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing or not a number */ public JsonContentAssert hasJsonPathNumberValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(Number.class, "a number"); return this; } /** * Verify that the actual value at the given JSON path produces a non-null boolean * result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing or not a boolean */ public JsonContentAssert hasJsonPathBooleanValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(Boolean.class, "a boolean"); return this; } /** * Verify that the actual value at the given JSON path produces a non-null array * result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing or not an array */ public JsonContentAssert hasJsonPathArrayValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(List.class, "an array"); return this; } /** * Verify that the actual value at the given JSON path produces a non-null map result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is missing or not a map */ public JsonContentAssert hasJsonPathMapValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasValue(Map.class, "a map"); return this; } /** * Verify that the actual value at the given JSON path produces an * {@link ObjectUtils#isEmpty(Object) empty} result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is not empty */ public JsonContentAssert hasEmptyJsonPathValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertHasEmptyValue(); return this; } /** * Verify that the actual value at the given JSON path produces no result. If the JSON * path expression is not {@linkplain JsonPath#isDefinite() definite}, this method * verifies that the value at the given path is <em>empty</em>. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is not missing */ public JsonContentAssert doesNotHaveJsonPathValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertDoesNotHaveValue(); return this; } /** * Verify that the actual value at the given JSON path does not produce an * {@link ObjectUtils#isEmpty(Object) empty} result. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return {@code this} assertion object * @throws AssertionError if the value at the given path is empty */ public JsonContentAssert doesNotHaveEmptyJsonPathValue(CharSequence expression, Object... args) { new JsonPathValue(expression, args).assertDoesNotHaveEmptyValue(); return this; } /** * Extract the value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid */ public AbstractObjectAssert<?, Object> extractingJsonPathValue( CharSequence expression, Object... args) { return Assertions.assertThat(new JsonPathValue(expression, args).getValue(false)); } /** * Extract the string value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid or does not result in a string */ public AbstractCharSequenceAssert<?, String> extractingJsonPathStringValue( CharSequence expression, Object... args) { return Assertions.assertThat( extractingJsonPathValue(expression, args, String.class, "a string")); } /** * Extract the number value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid or does not result in a number */ public AbstractObjectAssert<?, Number> extractingJsonPathNumberValue( CharSequence expression, Object... args) { return Assertions.assertThat( extractingJsonPathValue(expression, args, Number.class, "a number")); } /** * Extract the boolean value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid or does not result in a boolean */ public AbstractBooleanAssert<?> extractingJsonPathBooleanValue( CharSequence expression, Object... args) { return Assertions.assertThat( extractingJsonPathValue(expression, args, Boolean.class, "a boolean")); } /** * Extract the array value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid or does not result in an array */ @SuppressWarnings("unchecked") public AbstractListAssert<?, ?, Object, ObjectAssert<Object>> extractingJsonPathArrayValue( CharSequence expression, Object... args) { return Assertions.assertThat( extractingJsonPathValue(expression, args, List.class, "an array")); } /** * Extract the map value at the given JSON path for further object assertions. * @param expression the {@link JsonPath} expression * @param args arguments to parameterize the {@code JsonPath} expression with, using * formatting specifiers defined in {@link String#format(String, Object...)} * @return a new assertion object whose object under test is the extracted item * @throws AssertionError if the path is not valid or does not result in a map */ @SuppressWarnings("unchecked") public AbstractMapAssert<?, ?, Object, Object> extractingJsonPathMapValue( CharSequence expression, Object... args) { return Assertions.assertThat( extractingJsonPathValue(expression, args, Map.class, "a map")); } @SuppressWarnings("unchecked") private <T> T extractingJsonPathValue(CharSequence expression, Object[] args, Class<T> type, String expectedDescription) { JsonPathValue value = new JsonPathValue(expression, args); if (value.getValue(false) != null) { value.assertHasValue(type, expectedDescription); } return (T) value.getValue(false); } private JSONCompareResult compare(CharSequence expectedJson, JSONCompareMode compareMode) { if (this.actual == null) { return compareForNull(expectedJson); } try { return JSONCompare.compareJSON( (expectedJson == null ? null : expectedJson.toString()), this.actual.toString(), compareMode); } catch (Exception ex) { if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } throw new IllegalStateException(ex); } } private JSONCompareResult compare(CharSequence expectedJson, JSONComparator comparator) { if (this.actual == null) { return compareForNull(expectedJson); } try { return JSONCompare.compareJSON( (expectedJson == null ? null : expectedJson.toString()), this.actual.toString(), comparator); } catch (Exception ex) { if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } throw new IllegalStateException(ex); } } private JSONCompareResult compareForNull(CharSequence expectedJson) { JSONCompareResult result = new JSONCompareResult(); result.passed(); if (expectedJson != null) { result.fail("Expected null JSON"); } return result; } private JsonContentAssert assertNotFailed(JSONCompareResult result) { if (result.failed()) { throw new AssertionError("JSON Comparison failure: " + result.getMessage()); } return this; } private JsonContentAssert assertNotPassed(JSONCompareResult result) { if (result.passed()) { throw new AssertionError("JSON Comparison failure: " + result.getMessage()); } return this; } /** * A {@link JsonPath} value. */ private class JsonPathValue { private final String expression; private final JsonPath jsonPath; JsonPathValue(CharSequence expression, Object... args) { org.springframework.util.Assert.hasText( (expression == null ? null : expression.toString()), "expression must not be null or empty"); this.expression = String.format(expression.toString(), args); this.jsonPath = JsonPath.compile(this.expression); } public void assertHasEmptyValue() { if (ObjectUtils.isEmpty(getValue(false)) || isIndefiniteAndEmpty()) { return; } throw new AssertionError(getExpectedValueMessage("an empty value")); } public void assertDoesNotHaveEmptyValue() { if (!ObjectUtils.isEmpty(getValue(false))) { return; } throw new AssertionError(getExpectedValueMessage("a non-empty value")); } public void assertHasValue(Class<?> type, String expectedDescription) { Object value = getValue(true); if (value == null || isIndefiniteAndEmpty()) { throw new AssertionError(getNoValueMessage()); } if (type != null && !type.isInstance(value)) { throw new AssertionError(getExpectedValueMessage(expectedDescription)); } } public void assertDoesNotHaveValue() { if (getValue(false) == null || isIndefiniteAndEmpty()) { return; } throw new AssertionError(getExpectedValueMessage("no value")); } private boolean isIndefiniteAndEmpty() { return !isDefinite() && isEmpty(); } private boolean isDefinite() { return this.jsonPath.isDefinite(); } private boolean isEmpty() { return ObjectUtils.isEmpty(getValue(false)); } public Object getValue(boolean required) { try { CharSequence json = JsonContentAssert.this.actual; return this.jsonPath.read(json == null ? null : json.toString()); } catch (Exception ex) { if (!required) { return null; } throw new AssertionError(getNoValueMessage() + ". " + ex.getMessage()); } } private String getNoValueMessage() { return "No value at JSON path \"" + this.expression + "\""; } private String getExpectedValueMessage(String expectedDescription) { return String.format("Expected %s at JSON path \"%s\" but found: %s", expectedDescription, this.expression, ObjectUtils.nullSafeToString( StringUtils.quoteIfString(getValue(false)))); } } }