Skip to content

Commit

Permalink
Merge pull request #364 from lukas-krecan/fix-contains
Browse files Browse the repository at this point in the history
#361 Fix containsEntry
  • Loading branch information
lukas-krecan authored May 23, 2021
2 parents 1b87046 + f5686e5 commit a51256a
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.assertj.core.api.BigIntegerAssert;
import org.assertj.core.api.BooleanAssert;
import org.assertj.core.api.ListAssert;
import org.assertj.core.api.MapAssert;
import org.assertj.core.api.StringAssert;
import org.assertj.core.api.UriAssert;
import org.assertj.core.description.Description;
Expand Down Expand Up @@ -127,7 +126,7 @@ public JsonAssert isEqualTo(@Nullable Object expected) {
*/
@NotNull
@SuppressWarnings("unchecked")
public MapAssert<String, Object> isObject() {
public JsonMapAssert isObject() {
Node node = assertType(OBJECT);
return new JsonMapAssert((Map<String, Object>) node.getValue(), path.asPrefix(), configuration)
.as("Different value found in node \"%s\"", path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,32 @@
import net.javacrumbs.jsonunit.core.internal.Diff;
import net.javacrumbs.jsonunit.core.internal.Node;
import net.javacrumbs.jsonunit.core.internal.Path;
import org.assertj.core.api.MapAssert;
import org.assertj.core.api.AbstractMapAssert;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import static java.util.Arrays.stream;
import static java.util.Objects.deepEquals;
import static java.util.stream.Collectors.toList;
import static net.javacrumbs.jsonunit.core.internal.JsonUtils.wrapDeserializedObject;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.error.ShouldContain.shouldContain;
import static org.assertj.core.error.ShouldContainAnyOf.shouldContainAnyOf;
import static org.assertj.core.error.ShouldContainValue.shouldContainValue;
import static org.assertj.core.error.ShouldNotContainValue.shouldNotContainValue;
import static org.assertj.core.util.Arrays.array;

class JsonMapAssert extends MapAssert<String, Object> {
public class JsonMapAssert extends AbstractMapAssert<JsonMapAssert, Map<String, Object>, String, Object> {
private final Configuration configuration;
private final Path path;

JsonMapAssert(Map<String, Object> actual, Path path, Configuration configuration) {
super(actual);
super(actual, JsonMapAssert.class);
this.path = path;
this.configuration = configuration;
usingComparator(new JsonComparator(configuration, path.asPrefix(), true));
Expand All @@ -47,7 +58,7 @@ public JsonMapAssert isEqualTo(@Nullable Object expected) {

@Override
@NotNull
public MapAssert<String, Object> containsValue(@Nullable Object expected) {
public JsonMapAssert containsValue(@Nullable Object expected) {
if (expected instanceof Node) {
if (!contains(expected)) {
throwAssertionError(shouldContainValue(actual, expected));
Expand All @@ -60,7 +71,7 @@ public MapAssert<String, Object> containsValue(@Nullable Object expected) {

@Override
@NotNull
public MapAssert<String, Object> doesNotContainValue(@Nullable Object expected) {
public JsonMapAssert doesNotContainValue(@Nullable Object expected) {
if (expected instanceof Node) {
if (contains(expected)) {
throwAssertionError(shouldNotContainValue(actual, expected));
Expand All @@ -81,49 +92,134 @@ public JsonMapAssert isEqualToIgnoringGivenFields(@Nullable Object other, @NotNu
@Override
@NotNull
@Deprecated
public MapAssert<String, Object> isEqualToComparingOnlyGivenFields(@Nullable Object other, @NotNull String... propertiesOrFieldsUsedInComparison) {
public JsonMapAssert isEqualToComparingOnlyGivenFields(@Nullable Object other, @NotNull String... propertiesOrFieldsUsedInComparison) {
throw unsupportedOperation();
}

@Override
@NotNull
@Deprecated
public MapAssert<String, Object> isEqualToIgnoringNullFields(@Nullable Object other) {
public JsonMapAssert isEqualToIgnoringNullFields(@Nullable Object other) {
throw unsupportedOperation();
}

@Override
@NotNull
@Deprecated
public MapAssert<String, Object> isEqualToComparingFieldByField(@Nullable Object other) {
public JsonMapAssert isEqualToComparingFieldByField(@Nullable Object other) {
throw unsupportedOperation();
}

@Override
@NotNull
@Deprecated
public MapAssert<String, Object> isEqualToComparingFieldByFieldRecursively(@Nullable Object other) {
public JsonMapAssert isEqualToComparingFieldByFieldRecursively(@Nullable Object other) {
throw unsupportedOperation();
}

@Override
public JsonMapAssert containsEntry(String key, Object value) {
return contains(array(entry(key, value)));
}

@SafeVarargs
@Override
public final JsonMapAssert containsAnyOf(Entry<? extends String, ?>... entries) {
boolean anyMatch = stream(entries).anyMatch(this::doesContainEntry);
if (!anyMatch) {
throwAssertionError(shouldContainAnyOf(actual, entries));
}
return this;
}

@Override
public JsonMapAssert containsAllEntriesOf(Map<? extends String, ?> other) {
return contains(toEntries(other));
}

/**
* This method does not support JsonUnit features. Prefer {@link #containsOnly(Entry[])}
*/
@SafeVarargs
@Override
@Deprecated
public final JsonMapAssert containsExactly(Entry<? extends String, ?>... entries) {
return super.containsExactly(entries);
}

/**
* This method does not support JsonUnit features. Prefer {@link #containsOnly(Entry[])}
*/
@Override
@Deprecated
public JsonMapAssert containsExactlyEntriesOf(Map<? extends String, ?> map) {
return super.containsExactlyEntriesOf(map);
}

@SafeVarargs
@Override
public final JsonMapAssert containsOnly(Entry<? extends String, ?>... expected) {
Map<? extends String, ?> expectedAsMap = stream(expected).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
return isEqualTo(wrapDeserializedObject(expectedAsMap));
}

@NotNull
private List<Entry<? extends String, ?>> entriesNotFoundInMap(Entry<? extends String, ?>[] expected) {
return stream(expected).filter(entry -> !doesContainEntry(entry)).collect(toList());
}

@Override
@SafeVarargs
public final JsonMapAssert contains(Entry<? extends String, ?>... expected) {
List<Entry<? extends String, ?>> notFound = entriesNotFoundInMap(expected);
if (!notFound.isEmpty()) {
throwAssertionError(shouldContain(actual, expected, notFound));
}
return this;
}

private boolean doesContainEntry(Entry<? extends String, ?> entry) {
String key = entry.getKey();
if (!actual.containsKey(key)) {
return false;
}
Object actualValue = actual.get(key);
if (entry.getValue() instanceof Node) {
Node value = (Node) entry.getValue();
return isSimilar(actualValue, value);
} else {
return deepEquals(actualValue, entry.getValue());
}
}

@Override
public JsonMapAssert containsValues(Object... values) {
stream(values).forEach(this::containsValue);
return this;
}

@SuppressWarnings("unchecked")
private Entry<? extends String, ?>[] toEntries(Map<? extends String, ?> map) {
return map.entrySet().toArray(new Entry[0]);
}

/**
* Does not work. Use {@link #containsKey(Object)} instead.
* https://github.com/lukas-krecan/JsonUnit/issues/324
*/
@Override
@Deprecated
public MapAssert<String, Object> hasFieldOrProperty(String name) {
public JsonMapAssert hasFieldOrProperty(String name) {
return super.hasFieldOrProperty(name);
}

/**
* Does not work. Use {@link #contains(Map.Entry[])} instead.
* Does not work. Use {@link #contains(Entry[])} instead.
* https://github.com/lukas-krecan/JsonUnit/issues/324
*/
@Override
@Deprecated
public MapAssert<String, Object> hasFieldOrPropertyWithValue(String name, Object value) {
public JsonMapAssert hasFieldOrPropertyWithValue(String name, Object value) {
return super.hasFieldOrPropertyWithValue(name, value);
}

Expand All @@ -132,7 +228,7 @@ public MapAssert<String, Object> hasFieldOrPropertyWithValue(String name, Object
*/
@Override
@Deprecated
public MapAssert<String, Object> hasAllNullFieldsOrProperties() {
public JsonMapAssert hasAllNullFieldsOrProperties() {
return super.hasAllNullFieldsOrProperties();
}

Expand All @@ -141,7 +237,7 @@ public MapAssert<String, Object> hasAllNullFieldsOrProperties() {
*/
@Override
@Deprecated
public MapAssert<String, Object> hasAllNullFieldsOrPropertiesExcept(String... propertiesOrFieldsToIgnore) {
public JsonMapAssert hasAllNullFieldsOrPropertiesExcept(String... propertiesOrFieldsToIgnore) {
return super.hasAllNullFieldsOrPropertiesExcept(propertiesOrFieldsToIgnore);
}

Expand All @@ -150,16 +246,16 @@ public MapAssert<String, Object> hasAllNullFieldsOrPropertiesExcept(String... pr
*/
@Deprecated
@Override
public MapAssert<String, Object> hasNoNullFieldsOrProperties() {
public JsonMapAssert hasNoNullFieldsOrProperties() {
return super.hasNoNullFieldsOrProperties();
}

/**
* Does not work. https://github.com/lukas-krecan/JsonUnit/issues/324
*/
@Override
@Deprecated
public MapAssert<String, Object> hasNoNullFieldsOrPropertiesExcept(String... propertiesOrFieldsToIgnore) {
public JsonMapAssert hasNoNullFieldsOrPropertiesExcept(String... propertiesOrFieldsToIgnore) {
return super.hasNoNullFieldsOrPropertiesExcept(propertiesOrFieldsToIgnore);
}

Expand All @@ -177,6 +273,10 @@ private JsonMapAssert compare(@Nullable Object other, @NotNull Configuration con
}

private boolean contains(Object expected) {
return actual.entrySet().stream().anyMatch(kv -> Diff.create(expected, kv.getValue(), "fullJson", path.asPrefix(), configuration).similar());
return actual.entrySet().stream().anyMatch(entry -> isSimilar(entry.getValue(), expected));
}

private boolean isSimilar(Object actual, Object expected) {
return Diff.create(expected, actual, "fullJson", path.asPrefix(), configuration).similar();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,109 @@ void shouldFailCorrectlyOnNull() {
).hasMessage("JSON documents are different:\nDifferent value found in node \"\", expected: <1> but was: <null>.\n");
}

@Test
void containsEntryShouldWork() {
String entryValue = "{\n" +
" \"approvable\" : true," +
" \"rejectable\" : false" +
"}";

String input = "[{\"allowedActions\":" + entryValue + "}]";

assertThatJson(input,
body -> body.isArray().hasSize(1),
body -> body.inPath("[0]").isObject().containsEntry("allowedActions", json(entryValue)),
body -> body.inPath("[0]").isObject().contains(entry("allowedActions", json(entryValue))),
body -> body.inPath("[0]").isObject().containsAllEntriesOf(singletonMap("allowedActions", json(entryValue))),
body -> body.inPath("[0]").isObject().containsAnyOf(entry("allowedActions", json(entryValue)), entry("test", 1)),
body -> body.inPath("[0]").isObject().containsExactlyInAnyOrderEntriesOf(singletonMap("allowedActions", json(entryValue))),
body -> body.inPath("[0]").isObject().containsOnly(entry("allowedActions", json(entryValue))),
body -> body.inPath("[0]").isObject().containsValues(json(entryValue)),
body -> body.inPath("[0]").isObject().containsValue(json(entryValue)),
body -> body.inPath("[0].allowedActions").isObject().isEqualTo(json(entryValue))
);
}

@Test
void containsEntryShouldWorkWithMatcher() {
String json = "{\"a\": 1, \"b\": 2}";
assertThatJson(json).isObject().containsEntry("a", json("\"${json-unit.any-number}\""));
assertThatJson(json).isObject().contains(entry("a", json("\"${json-unit.any-number}\"")));
}

@Test
void containsOnlyShouldWorkWithMatcher() {
String json = "{\"a\": 1, \"b\": 2}";
assertThatJson(json).isObject().containsOnly(
entry("a", json("\"${json-unit.any-number}\"")),
entry("b", json("\"${json-unit.any-number}\""))
);
}

@Test
void containsEntryShouldFailWithMatcher() {
String json = "{\"a\": 1, \"b\": 2}";

assertThatThrownBy(() ->
assertThatJson(json).isObject().contains(
entry("a", json("\"${json-unit.any-string}\"")),
entry("b", json("\"${json-unit.any-number}\""))
)
).hasMessage("[Different value found in node \"\"] \n" +
"Expecting map:\n" +
" {\"a\":1,\"b\":2}\n" +
"to contain:\n" +
" [MapEntry[key=\"a\", value=\"${json-unit.any-string}\"],\n" +
" MapEntry[key=\"b\", value=\"${json-unit.any-number}\"]]\n" +
"but could not find the following map entries:\n" +
" [MapEntry[key=\"a\", value=\"${json-unit.any-string}\"]]\n");
}

@Test
void containsAnyOfShouldWorkWithMatcher() {
String json = "{\"a\": 1, \"b\": 2}";
assertThatJson(json).isObject().containsAnyOf(
entry("a", json("\"${json-unit.any-string}\"")),
entry("a", json("\"${json-unit.any-number}\""))
);
}

@Test
void containsAnyOfShouldFailWithMatcher() {
String json = "{\"a\": 1, \"b\": 2}";

assertThatThrownBy(() ->
assertThatJson(json).isObject().containsAnyOf(
entry("a", json("\"${json-unit.any-string}\"")),
entry("b", json("\"${json-unit.any-string}\""))
)
).hasMessage("[Different value found in node \"\"] \n" +
"Expecting:\n" +
" {\"a\":1,\"b\":2}\n" +
"to contain at least one of the following elements:\n" +
" [MapEntry[key=\"a\", value=\"${json-unit.any-string}\"],\n" +
" MapEntry[key=\"b\", value=\"${json-unit.any-string}\"]]\n" +
"but none were found ");
}

@Test
void containsValuesShouldPass() {
String json = "{\"a\": 1, \"b\": 2}";
assertThatJson(json).isObject().containsValues(valueOf(1), valueOf(2), json("\"${json-unit.any-number}\""));
}

@Test
void containsValuesShouldFail() {
String json = "{\"a\": 1, \"b\": 2}";
assertThatThrownBy(() ->
assertThatJson(json).isObject().containsValues(valueOf(1), valueOf(2), json("\"${json-unit.any-string}\""))
).hasMessage("[Different value found in node \"\"] \n" +
"Expecting:\n" +
" {\"a\":1,\"b\":2}\n" +
"to contain value:\n" +
" \"${json-unit.any-string}\"");
}

@Test
void absentOnArray() {
String json = "[{\"a\":1},{\"b\":1}]";
Expand Down

0 comments on commit a51256a

Please sign in to comment.