Assertj json extension (#6039)
* Assertj json extension * Allow chained invocations * Rename --------- Co-authored-by: juan.marchionatto <juan.marchionatto@smilecdr.com>
This commit is contained in:
parent
90251b31ab
commit
bc8d873c7f
|
@ -0,0 +1,367 @@
|
||||||
|
package ca.uhn.test.util;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.assertj.core.api.AbstractAssert;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.assertj.core.api.SoftAssertions;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Fail.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertj extension to ease testing json strings with few nested quoted strings
|
||||||
|
*/
|
||||||
|
public class AssertJson extends AbstractAssert<AssertJson, String> {
|
||||||
|
|
||||||
|
public AssertJson(String actual) {
|
||||||
|
super(actual, AssertJson.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssertJson assertThat(String actual) {
|
||||||
|
return new AssertJson(actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasPath(String thePath) {
|
||||||
|
isNotNull();
|
||||||
|
isNotEmpty(thePath);
|
||||||
|
|
||||||
|
Assertions.assertThat(isJsonObjStr(actual)).isTrue();
|
||||||
|
Map<String, Object> actualMap = getMap(actual);
|
||||||
|
Assertions.assertThat(actualMap).isNotNull();
|
||||||
|
getPathMap(thePath);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssertJson isNotEmpty(String thePath) {
|
||||||
|
Assertions.assertThat(thePath).isNotEmpty();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasKeys(String... theKeys) {
|
||||||
|
isNotNull();
|
||||||
|
|
||||||
|
Map<String, Object> map = getMap(actual);
|
||||||
|
Assertions.assertThat(map).isNotNull();
|
||||||
|
|
||||||
|
Assertions.assertThat(
|
||||||
|
map.keySet()).containsAll(Arrays.asList(theKeys));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasExactlyKeys(String... theKeys) {
|
||||||
|
isNotNull();
|
||||||
|
|
||||||
|
Map<String, Object> map = getMap(actual);
|
||||||
|
Assertions.assertThat(map).isNotNull();
|
||||||
|
|
||||||
|
Assertions.assertThat(
|
||||||
|
map.keySet()).hasSameElementsAs(Arrays.asList(theKeys));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasExactlyKeysWithValues(List<String> theKeys, List<? extends Serializable> theValues) {
|
||||||
|
isNotNull();
|
||||||
|
|
||||||
|
if (!checkSizes(theKeys.size(), theValues.size())) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> map = getMap(actual);
|
||||||
|
Assertions.assertThat(map).isNotNull();
|
||||||
|
|
||||||
|
Assertions.assertThat(
|
||||||
|
map.keySet()).hasSameElementsAs(theKeys);
|
||||||
|
|
||||||
|
for (int i = 0; i <theKeys.size(); i++) {
|
||||||
|
hasKeyWithValue(theKeys.get(i), theValues.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AssertJson hasKeyWithValue(String theKey, Object theExpectedValue) {
|
||||||
|
isNotNull();
|
||||||
|
|
||||||
|
Map<String, Object> actualMap = getMap(actual);
|
||||||
|
Assertions.assertThat(actualMap).isNotNull();
|
||||||
|
Object actualValue = actualMap.get(theKey);
|
||||||
|
|
||||||
|
JsonTestTypes actualValueType = getType(actualValue);
|
||||||
|
JsonTestTypes expectedValueType = getType(theExpectedValue);
|
||||||
|
|
||||||
|
if (actualValueType != expectedValueType) {
|
||||||
|
fail(getDifferentTypesMessage(theKey, actualValueType, expectedValueType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonObjStr(theExpectedValue)) {
|
||||||
|
assertJsonObject(actualMap, theKey, theExpectedValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonList(theExpectedValue)) {
|
||||||
|
assertJsonList(actualMap, theKey, theExpectedValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assertions.assertThat(actualMap)
|
||||||
|
.extracting(theKey)
|
||||||
|
.isEqualTo(theExpectedValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertJsonList(Map<String, Object> theActualMap, String theKey, Object theExpectedValue) {
|
||||||
|
List<?> expectedValueList = getList((String) theExpectedValue);
|
||||||
|
Assertions.assertThat(expectedValueList).isNotNull();
|
||||||
|
|
||||||
|
Assertions.assertThat(theActualMap.get(theKey)).isNotNull().isInstanceOf(Collection.class);
|
||||||
|
List<?> actualValueList = (List<?>) theActualMap.get(theKey);
|
||||||
|
|
||||||
|
Assertions.assertThat(actualValueList)
|
||||||
|
.asList()
|
||||||
|
.hasSameElementsAs(expectedValueList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonTestTypes getType(Object theValue) {
|
||||||
|
if (theValue instanceof Map<?, ?>) {
|
||||||
|
return JsonTestTypes.JSON_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonObjStr(theValue)) {
|
||||||
|
getMap((String) theValue);
|
||||||
|
return JsonTestTypes.JSON_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonList(theValue)) {
|
||||||
|
return JsonTestTypes.JSON_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonTestTypes.STRING_NOT_JSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDifferentTypesMessage(String theKey, JsonTestTypes theActualValueType, JsonTestTypes theExpectedValueType) {
|
||||||
|
return "Types mismatch. Te expected " + (theKey == null ? " " : "'" + theKey + "' ") +
|
||||||
|
"value is a " + theExpectedValueType.myDisplay +
|
||||||
|
" whereas the actual value is a " + theActualValueType.myDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isJsonList(Object theValue) {
|
||||||
|
return theValue instanceof Collection<?> ||
|
||||||
|
(theValue instanceof String stringValue
|
||||||
|
&& stringValue.trim().startsWith("[")
|
||||||
|
&& stringValue.trim().endsWith("]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertJsonObject(Map<String, Object> theActualMap, String theKey, Object theValue) {
|
||||||
|
Map<String, Object> expectedValueMap = getMap((String) theValue);
|
||||||
|
Assertions.assertThat(expectedValueMap).isNotNull();
|
||||||
|
|
||||||
|
Assertions.assertThat(theActualMap.get(theKey)).isNotNull().isInstanceOf(Map.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> actualValueMap = (Map<String, Object>) theActualMap.get(theKey);
|
||||||
|
|
||||||
|
SoftAssertions lazyly = new SoftAssertions();
|
||||||
|
for (String key : actualValueMap.keySet()) {
|
||||||
|
lazyly.assertThat(actualValueMap)
|
||||||
|
.as("Unexpected value for key: " + key + ":")
|
||||||
|
.extracting(key).isEqualTo(expectedValueMap.get(key));
|
||||||
|
}
|
||||||
|
lazyly.assertAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isJsonObjStr(Object theValue) {
|
||||||
|
if (theValue instanceof String strValue) {
|
||||||
|
String trimmed = trimAll(strValue);
|
||||||
|
return trimmed.startsWith("{") && trimmed.endsWith("}") && isValidJson(trimmed);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trimAll(String theString) {
|
||||||
|
return theString.trim().replace("\n", "").replace("\t", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidJson(String theStrValue) {
|
||||||
|
getMap(theStrValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasKeysWithValues(List<String> theKeys, List<Object> theValues) {
|
||||||
|
isNotNull();
|
||||||
|
|
||||||
|
checkSizes(theKeys.size(), theValues.size());
|
||||||
|
|
||||||
|
Map<String, Object> map = getMap(actual);
|
||||||
|
|
||||||
|
Assertions.assertThat(map).isNotNull();
|
||||||
|
Assertions.assertThat(map.keySet()).containsAll(theKeys);
|
||||||
|
checkKeysAndValues(map, theKeys, theValues);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkKeysAndValues(Map<String, Object> theExpected, List<String> theKeys, List<Object> theValues) {
|
||||||
|
SoftAssertions lazyly = new SoftAssertions();
|
||||||
|
for (int i = 0; i < theKeys.size(); i++) {
|
||||||
|
lazyly.assertThat(theExpected)
|
||||||
|
.as("Unexpected value for key: " + theKeys.get(i) + ":")
|
||||||
|
.extracting(theKeys.get(i)).isEqualTo(theValues.get(i));
|
||||||
|
}
|
||||||
|
lazyly.assertAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkSizes(int keysSize, int valuesSize) {
|
||||||
|
if (keysSize != valuesSize) {
|
||||||
|
fail("Keys and values should have same size. Received " + keysSize + " keys and " + valuesSize + " values.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Map<String, Object> getMap(String theJsonString) {
|
||||||
|
try {
|
||||||
|
return new ObjectMapper()
|
||||||
|
.readValue(new ByteArrayInputStream(theJsonString.getBytes()), new TypeReference<>() {});
|
||||||
|
|
||||||
|
} catch (IOException theE) {
|
||||||
|
fail("IOException: " + theE);
|
||||||
|
}
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<?> getList(String theJsonString) {
|
||||||
|
try {
|
||||||
|
return new ObjectMapper()
|
||||||
|
.readValue(new ByteArrayInputStream(theJsonString.getBytes()), new TypeReference<>() {});
|
||||||
|
|
||||||
|
} catch (IOException theE) {
|
||||||
|
fail("IOException: " + theE);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AssertJson hasPaths(String... thePaths) {
|
||||||
|
for (String path : thePaths) {
|
||||||
|
hasPath(path);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasPathWithValue(String thePath, String theValue) {
|
||||||
|
String[] pathElements = thePath.split("\\.");
|
||||||
|
if (pathElements.length == 1) {
|
||||||
|
hasKeyWithValue(thePath, theValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> pathMap = getPathMap(thePath);
|
||||||
|
String lastPathElement = pathElements[pathElements.length - 1];
|
||||||
|
|
||||||
|
if (isJsonObjStr(theValue)) {
|
||||||
|
Assertions.assertThat(pathMap)
|
||||||
|
.extracting(lastPathElement)
|
||||||
|
.isEqualTo(getMap(theValue));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isJsonList(theValue)) {
|
||||||
|
Assertions.assertThat(pathMap)
|
||||||
|
.extracting(lastPathElement)
|
||||||
|
.asList()
|
||||||
|
.hasSameElementsAs(getList(theValue));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check last path element's value
|
||||||
|
Assertions.assertThat(pathMap)
|
||||||
|
.extracting(pathElements[pathElements.length-1])
|
||||||
|
.isEqualTo(theValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssertJson hasPathsWithValues(List<String> thePaths, List<String> theValues) {
|
||||||
|
if (thePaths.size() != theValues.size()) {
|
||||||
|
fail("Paths size (" + thePaths.size() + ") is different than values size (" + theValues.size() + ")");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < thePaths.size(); i++) {
|
||||||
|
hasPathWithValue(thePaths.get(i), theValues.get(i));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getPathMap(String thePath) {
|
||||||
|
String[] pathElements = thePath.split("\\.");
|
||||||
|
StringBuilder pathSoFar = new StringBuilder();
|
||||||
|
|
||||||
|
Map<String, Object> pathMap = getMap(actual);
|
||||||
|
|
||||||
|
for (int i = 0; i < pathElements.length-1; i++) {
|
||||||
|
String pathElement = pathElements[i];
|
||||||
|
pathSoFar.append(StringUtils.isNotEmpty(pathSoFar) ? "." + pathElement : pathElement);
|
||||||
|
Object pathValue = pathMap.get(pathElement);
|
||||||
|
|
||||||
|
// all path values, other than the last, must be json objects (maps)
|
||||||
|
assertIsJsonObject(pathSoFar.toString(), pathValue);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> aMap = (Map<String, Object>) pathValue;
|
||||||
|
pathMap = aMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIsJsonObject(String thePath, Object theValue) {
|
||||||
|
if (theValue instanceof Map<?, ?>) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theValue instanceof String stringValue) {
|
||||||
|
if (!isJsonObjStr(theValue)) {
|
||||||
|
fail(thePath + " doesn't contain a json object but a plain string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
getMap(stringValue);
|
||||||
|
} catch (Exception theE) {
|
||||||
|
fail(thePath + " doesn't contain a json object");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = "Path: " + thePath + "' is not a json object but a Json list";
|
||||||
|
if (isJsonList(theValue)) {
|
||||||
|
Assertions.assertThat(theValue)
|
||||||
|
.as(msg)
|
||||||
|
.isInstanceOf(Map.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum JsonTestTypes {
|
||||||
|
|
||||||
|
STRING_NOT_JSON("plain string (not json)"),
|
||||||
|
JSON_OBJECT("json object"),
|
||||||
|
JSON_LIST("json list"),
|
||||||
|
JSON_STRING("json string");
|
||||||
|
|
||||||
|
final String myDisplay;
|
||||||
|
|
||||||
|
JsonTestTypes(String theDisplay) {
|
||||||
|
myDisplay = theDisplay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,465 @@
|
||||||
|
package ca.uhn.fhir.test.utilities;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ca.uhn.test.util.AssertJson.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
class AssertJsonTest {
|
||||||
|
|
||||||
|
private final String myJsonString = """
|
||||||
|
{
|
||||||
|
"firstName": "John",
|
||||||
|
"lastName": "Smith",
|
||||||
|
"age": 25,
|
||||||
|
"address": {
|
||||||
|
"streetAddress": "21 2nd Street",
|
||||||
|
"city": "New York",
|
||||||
|
"state": "NY",
|
||||||
|
"postalCode": 10021
|
||||||
|
},
|
||||||
|
"phoneNumbers": [
|
||||||
|
{
|
||||||
|
"type": "home",
|
||||||
|
"number": "212 555-1234"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "fax",
|
||||||
|
"number": "646 555-4567"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
String goodAddress = """
|
||||||
|
{
|
||||||
|
"streetAddress": "21 2nd Street",
|
||||||
|
"city": "New York",
|
||||||
|
"state": "NY",
|
||||||
|
"postalCode": 10021
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
String wrongAddress = """
|
||||||
|
{
|
||||||
|
"streetAddress": "432 Hillcrest Rd",
|
||||||
|
"city": "Mississauga",
|
||||||
|
"state": "ON",
|
||||||
|
"postalCode": 10021
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
String goodPhoneNumbers = """
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "home",
|
||||||
|
"number": "212 555-1234"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "fax",
|
||||||
|
"number": "646 555-4567"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""";
|
||||||
|
|
||||||
|
String wrongPhoneNumbers = """
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "cell",
|
||||||
|
"number": "212 555-9876"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "fax",
|
||||||
|
"number": "646 666-4567"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
""";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFluency() {
|
||||||
|
assertThat(myJsonString)
|
||||||
|
.hasPath("address.city")
|
||||||
|
.hasPaths("firstName", "address.city")
|
||||||
|
.hasKeys("firstName", "address")
|
||||||
|
.hasExactlyKeys("firstName", "lastName", "age", "address", "phoneNumbers")
|
||||||
|
.hasKeyWithValue("lastName", "Smith")
|
||||||
|
.hasKeysWithValues(
|
||||||
|
List.of("firstName", "lastName"),
|
||||||
|
List.of("John", "Smith"))
|
||||||
|
.hasExactlyKeysWithValues(
|
||||||
|
List.of("firstName", "lastName", "age", "address", "phoneNumbers"),
|
||||||
|
List.of("John", "Smith", 25, goodAddress, goodPhoneNumbers))
|
||||||
|
.hasPath("lastName");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasPath {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_success() {
|
||||||
|
assertThat(myJsonString).hasPath("address.city");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_fails_pathNotFound() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPath("address.city.neighbourhood"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("address.city doesn't contain a json object but a plain string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasPaths {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_success() {
|
||||||
|
assertThat(myJsonString).hasPaths("lastName", "address.city");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test_fails_pathNotFound() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPaths("lastName", "address.city.neighbourhood"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("address.city doesn't contain a json object but a plain string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasPathWithValue {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testStringValue_success() {
|
||||||
|
assertThat(myJsonString).hasPathWithValue("address.city", "New York");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedStringValue_failure_isList() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue(
|
||||||
|
"phoneNumbers.number",
|
||||||
|
"212 555-1234"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Path: phoneNumbers' is not a json object but a Json list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedStringValue_failure_isObject() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue(
|
||||||
|
"address",
|
||||||
|
"432 Hillcrest Rd"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Types mismatch. Te expected 'address' value is a plain string (not json) whereas the actual value is a json object");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedStringValue_failure_differentString() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue(
|
||||||
|
"address.streetAddress",
|
||||||
|
"181 Hillcrest Rd."))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("expected: \"181 Hillcrest Rd.\"")
|
||||||
|
.hasMessageContaining("but was: \"21 2nd Street\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedObjectValue_success() {
|
||||||
|
assertThat(myJsonString).hasPathWithValue("address", goodAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedObjectValue_failure_isString() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("age", goodAddress))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Types mismatch. Te expected 'age' value is a json object whereas the actual value is a plain string (not json)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedObjectValue_failure_isList() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("phoneNumbers", "223-217-5555"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Types mismatch. Te expected 'phoneNumbers' value is a plain string (not json) whereas the actual value is a json list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedObjectValue_failure_different() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("address", wrongAddress))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
Multiple Failures (3 failures)
|
||||||
|
-- failure 1 --
|
||||||
|
[Unexpected value for key: streetAddress:]\s
|
||||||
|
expected: "432 Hillcrest Rd"
|
||||||
|
but was: "21 2nd Street"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 2 --
|
||||||
|
[Unexpected value for key: city:]\s
|
||||||
|
expected: "Mississauga"
|
||||||
|
but was: "New York"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 3 --
|
||||||
|
[Unexpected value for key: state:]\s
|
||||||
|
expected: "ON"
|
||||||
|
but was: "NY"
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedListValue_success() {
|
||||||
|
assertThat(myJsonString).hasPathWithValue("phoneNumbers", goodPhoneNumbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedListValue_failure_isString() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("phoneNumbers", "222-555-7654"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Types mismatch. Te expected 'phoneNumbers' value is a plain string (not json) whereas the actual value is a json list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedListValue_failure_isObject() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("phoneNumbers", goodAddress))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Types mismatch. Te expected 'phoneNumbers' value is a json object whereas the actual value is a json list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testExpectedListValue_failure_different() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathWithValue("phoneNumbers", wrongPhoneNumbers))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("Expecting ArrayList:")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
element(s) not found:
|
||||||
|
[{"number"="212 555-9876", "type"="cell"},
|
||||||
|
{"number"="646 666-4567", "type"="fax"}]
|
||||||
|
and element(s) not expected:
|
||||||
|
[{"number"="212 555-1234", "type"="home"},
|
||||||
|
{"number"="646 555-4567", "type"="fax"}]
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasPathsWithValues {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_success() {
|
||||||
|
assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(goodPhoneNumbers, goodAddress, "Smith"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDifferentSizes_failure() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers"), List.of(goodPhoneNumbers, wrongPhoneNumbers)))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageStartingWith("Paths size (1) is different than values size (2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_wrongTypeString() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(goodPhoneNumbers, goodAddress, wrongAddress)))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessage("Types mismatch. Te expected 'lastName' value is a json object whereas the actual value is a plain string (not json)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_wrongTypeList() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of("Wesson", goodAddress, "Smith")))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessage("Types mismatch. Te expected 'phoneNumbers' value is a plain string (not json) whereas the actual value is a json list");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_wrongTypeObject() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(goodPhoneNumbers, "Wesson", "Smith")))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessage("Types mismatch. Te expected 'address' value is a plain string (not json) whereas the actual value is a json object");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_differentString() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(goodPhoneNumbers, goodAddress, "Wesson")))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("[Extracted: lastName]")
|
||||||
|
.hasMessageContaining("expected: \"Wesson\"")
|
||||||
|
.hasMessageContaining("but was: \"Smith\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_differentList() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(wrongPhoneNumbers, goodAddress, "Smith")))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
element(s) not found:
|
||||||
|
[{"number"="212 555-9876", "type"="cell"},
|
||||||
|
{"number"="646 666-4567", "type"="fax"}]
|
||||||
|
and element(s) not expected:
|
||||||
|
[{"number"="212 555-1234", "type"="home"},
|
||||||
|
{"number"="646 555-4567", "type"="fax"}]
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMixedValues_failure_differentObject() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasPathsWithValues(List.of("phoneNumbers", "address", "lastName"),
|
||||||
|
List.of(goodPhoneNumbers, wrongAddress, "Smith")))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
Multiple Failures (3 failures)
|
||||||
|
-- failure 1 --
|
||||||
|
[Unexpected value for key: streetAddress:]\s
|
||||||
|
expected: "432 Hillcrest Rd"
|
||||||
|
but was: "21 2nd Street"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 2 --
|
||||||
|
[Unexpected value for key: city:]\s
|
||||||
|
expected: "Mississauga"
|
||||||
|
but was: "New York"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 3 --
|
||||||
|
[Unexpected value for key: state:]\s
|
||||||
|
expected: "ON"
|
||||||
|
but was: "NY"
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasExactlyKeys() {
|
||||||
|
assertThat(myJsonString).hasExactlyKeys("firstName", "lastName", "age", "address", "phoneNumbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasExactlyKeys {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasExactlyKeys_succeeds() {
|
||||||
|
assertThat(myJsonString).hasExactlyKeys("firstName", "lastName", "age", "address", "phoneNumbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasExactlyKeys_fails() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString)
|
||||||
|
.hasExactlyKeys("firstName", "age", "address", "phoneNumbers", "extraKey"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
element(s) not found:
|
||||||
|
["extraKey"]""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
and element(s) not expected:
|
||||||
|
["lastName"]""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasKeysWithValues {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void hasExactlyKeysWithValues_succeeds() {
|
||||||
|
assertThat(myJsonString).hasKeysWithValues(
|
||||||
|
List.of("firstName", "lastName", "age"),
|
||||||
|
List.of("John", "Smith", 25));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testKeysAndValues_haveDifferentSizes_fails() {
|
||||||
|
assertThatThrownBy(() ->
|
||||||
|
assertThat(myJsonString).hasKeysWithValues(
|
||||||
|
List.of("firstName", "lastName", "age"),
|
||||||
|
List.of("John", "Wesson", 31, 28)))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessage("Keys and values should have same size. Received 3 keys and 4 values.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testKeysAndValues_haveDifferentValues_failsShowingAllProblems() {
|
||||||
|
assertThatThrownBy(() ->
|
||||||
|
assertThat(myJsonString).hasKeysWithValues(
|
||||||
|
List.of("firstName", "lastName", "age"),
|
||||||
|
List.of("John", "Wesson", 31)))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
Multiple Failures (2 failures)
|
||||||
|
-- failure 1 --
|
||||||
|
[Unexpected value for key: lastName:]\s
|
||||||
|
expected: "Wesson"
|
||||||
|
but was: "Smith"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 2 --
|
||||||
|
[Unexpected value for key: age:]\s
|
||||||
|
expected: 31
|
||||||
|
but was: 25
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasKeys {
|
||||||
|
@Test
|
||||||
|
void testSuccess() {
|
||||||
|
assertThat(myJsonString).hasKeys("address", "phoneNumbers");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasKeys("address", "weight"))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
but could not find the following element(s):
|
||||||
|
["weight"]
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class TestHasKeyWithValue {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSuccess() {
|
||||||
|
assertThat(myJsonString).hasKeyWithValue("address", goodAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure() {
|
||||||
|
assertThatThrownBy(() -> assertThat(myJsonString).hasKeyWithValue("address", wrongAddress))
|
||||||
|
.isInstanceOf(AssertionError.class)
|
||||||
|
.hasMessageContaining("""
|
||||||
|
Multiple Failures (3 failures)
|
||||||
|
-- failure 1 --
|
||||||
|
[Unexpected value for key: streetAddress:]\s
|
||||||
|
expected: "432 Hillcrest Rd"
|
||||||
|
but was: "21 2nd Street"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 2 --
|
||||||
|
[Unexpected value for key: city:]\s
|
||||||
|
expected: "Mississauga"
|
||||||
|
but was: "New York"
|
||||||
|
""")
|
||||||
|
.hasMessageContaining("""
|
||||||
|
-- failure 3 --
|
||||||
|
[Unexpected value for key: state:]\s
|
||||||
|
expected: "ON"
|
||||||
|
but was: "NY"
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue