Skip to content

Commit

Permalink
MapAssert.containsOnlyKeys (#63)
Browse files Browse the repository at this point in the history
* Adds more tests for MapAssert.containsOnly
* Adds assertion for MapAssert.containsOnlyKeys
  • Loading branch information
mchmielarz authored Mar 20, 2019
1 parent a0b5238 commit 4627e2c
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 41 deletions.
25 changes: 12 additions & 13 deletions src/main/java/org/assertj/vavr/api/AbstractMapAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@

import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.collection.Array;
import io.vavr.collection.HashMap;
import io.vavr.collection.List;
import io.vavr.collection.Map;
import io.vavr.collection.Set;

import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.EnumerableAssert;
import org.assertj.core.internal.ComparatorBasedComparisonStrategy;
Expand All @@ -30,8 +25,6 @@

import java.util.Comparator;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static org.assertj.core.error.ShouldBeEmpty.shouldBeEmpty;
Expand Down Expand Up @@ -193,6 +186,18 @@ public SELF doesNotContainEntry(KEY key, VALUE value) {
return myself;
}

public SELF containsOnly(Iterable<Tuple2<KEY, VALUE>> entries) {
isNotNull();
maps.assertContainsOnly(info, actual, entries);
return myself;
}

public SELF containsOnlyKeys(KEY... keys) {
isNotNull();
maps.assertContainsOnlyKeys(info, actual, keys);
return myself;
}

@Override
public SELF hasSize(int expectedSize) {
isNotNull();
Expand Down Expand Up @@ -230,10 +235,4 @@ public SELF usingDefaultElementComparator() {
elementComparisonStrategy = StandardComparisonStrategy.instance();
return myself;
}

public SELF containsOnly(Iterable<Tuple2<KEY, VALUE>> entries) {
isNotNull();
maps.assertContainsOnly(info, actual, entries);
return myself;
}
}
101 changes: 81 additions & 20 deletions src/main/java/org/assertj/vavr/internal/Maps.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
package org.assertj.vavr.internal;

import io.vavr.Tuple2;
import io.vavr.collection.Array;
import io.vavr.collection.HashMap;
import io.vavr.collection.Map;
import io.vavr.collection.Set;
import io.vavr.collection.*;
import org.assertj.core.api.AssertionInfo;
import org.assertj.core.error.ShouldContainAnyOf;
import org.assertj.core.error.ShouldNotBeNull;
import org.assertj.core.error.ShouldNotContainNull;
import org.assertj.core.internal.Failures;
import org.assertj.core.internal.Objects;

import java.util.function.Predicate;

import static org.assertj.core.error.ShouldContain.shouldContain;
import static org.assertj.core.error.ShouldNotContain.shouldNotContain;
import static org.assertj.core.error.ShouldContainOnly.shouldContainOnly;
import static org.assertj.core.error.ShouldContainOnlyKeys.shouldContainOnlyKeys;
import static org.assertj.core.error.ShouldNotContain.shouldNotContain;
import static org.assertj.core.internal.CommonValidations.failIfEmptySinceActualIsNotEmpty;
import static org.assertj.core.util.Objects.areEqual;
import static org.assertj.core.util.Preconditions.checkArgument;
Expand Down Expand Up @@ -99,6 +95,64 @@ public <K, V> void assertDoesNotContain(AssertionInfo info, Map<K, V> actual,
}
}

/**
* Asserts that the given {@code Map} contains the given entries only.
*
* @param <K> key type
* @param <V> value type
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param entries the entries that are expected to only be in the given {@code Map}.
* @throws AssertionError if the array of entries is {@code null}.
* @throws AssertionError if the array of entries is empty.
* @throws NullPointerException if any of the entries in the given array is {@code null}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} contains any of the given entries.
*/
public <K, V> void assertContainsOnly(AssertionInfo info, Map<K, V> actual, Iterable<Tuple2<K, V>> entries) {
assertNotNull(info, actual);
failIfNull(entries);
if (actual.isEmpty() && !entries.iterator().hasNext()) {
return;
}
failIfEmpty(entries);
Map<K, V> expected = HashMap.ofEntries(entries);
Map<K, V> notExpected = actual.filter(notContainFrom(expected));
if (!notExpected.isEmpty()) {
Map<K, V> notFound = expected.filter(notContainFrom(actual));
throw failures.failure(info, shouldContainOnly(actual, expected, notFound, notExpected));
}
}

/**
* Asserts that the given {@code Map} contains the given keys, in any order.
*
* @param <K> key type
* @param <V> value type
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param keys the keys that are expected to be in the given {@code Map}.
* @throws NullPointerException if the array of keys is {@code null}.
* @throws IllegalArgumentException if the array of keys is empty.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} does not contain the given keys.
*/
public <K, V> void assertContainsOnlyKeys(AssertionInfo info, Map<K, V> actual, K[] keys) {
assertNotNull(info, actual);
failIfNull(keys);
if (actual.isEmpty() && keys.length == 0) {
return;
}
failIfEmpty(keys);

Set<K> expected = HashSet.of(keys);
Set<K> notExpected = actual.keySet().filter(notContainFrom(expected));
if (!notExpected.isEmpty()) {
Set<K> notFound = expected.filter(notContainFrom(actual.keySet()));
throw failures.failure(info, shouldContainOnlyKeys(actual, expected, notFound, notExpected));
}
}

private <K, V> boolean containsEntry(Map<K, V> actual, Tuple2<? extends K, ? extends V> entry) {
checkNotNull(entry, "Entries to look for should not be null");
return actual.containsKey(entry._1) && areEqual(actual.get(entry._1).get(), entry._2);
Expand All @@ -108,6 +162,14 @@ private static <K, V> void failIfEmpty(Tuple2<? extends K, ? extends V>[] entrie
checkArgument(entries.length > 0, "The array of entries to look for should not be empty");
}

private static <K, V> void failIfEmpty(Iterable<Tuple2<K, V>> entries) {
checkArgument(entries.iterator().hasNext(), "The entries to look for should not be empty");
}

private static <K> void failIfEmpty(K[] keys) {
checkArgument(keys.length > 0, "The array of keys to look for should not be empty");
}

private static <K, V> void failIfNullOrEmpty(Tuple2<? extends K, ? extends V>[] entries) {
failIfNull(entries);
failIfEmpty(entries);
Expand All @@ -117,24 +179,23 @@ private static <K, V> void failIfNull(Tuple2<? extends K, ? extends V>[] entries
checkNotNull(entries, "The array of entries to look for should not be null");
}

private void assertNotNull(AssertionInfo info, Map<?, ?> actual) {
Objects.instance().assertNotNull(info, actual);
private static <K, V> void failIfNull(Iterable<Tuple2<K, V>> entries) {
checkNotNull(entries, "The entries to look for should not be null");
}

public <K, V> void assertContainsOnly(AssertionInfo info, Map<K, V> actual, Iterable<Tuple2<K, V>> entries) {
if (entries == null) {
throw failures.failure("Expected entries should not be null");
} else {
Map<K, V> expected = HashMap.ofEntries(entries);
Map<K, V> notExpected = actual.filter(notContainFrom(expected));
if (!notExpected.isEmpty()) {
Map<K, V> notFound = expected.filter(notContainFrom(actual));
throw failures.failure(info, shouldContainOnly(actual, expected, notFound, notExpected));
}
}
private static <K> void failIfNull(K[] keys) {
checkNotNull(keys, "The array of keys to look for should not be null");
}

private void assertNotNull(AssertionInfo info, Map<?, ?> actual) {
Objects.instance().assertNotNull(info, actual);
}

private static <K, V> Predicate<Tuple2<K, V>> notContainFrom(Map<K, V> map) {
return tuple -> !map.contains(tuple);
}

private static <K> Predicate<K> notContainFrom(Set<K> keys) {
return key -> !keys.contains(key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.assertj.vavr.api;

/*
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
* <p>
* Copyright 2012-2019 the original author or authors.
*/

import io.vavr.collection.HashMap;
import io.vavr.collection.Map;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.error.ShouldNotBeNull.shouldNotBeNull;
import static org.assertj.vavr.api.VavrAssertions.assertThat;

class MapAssert_containsOnlyKeys_Test {

@Test
void should_pass_if_Map_contains_only_given_keys() {
final Map<String, String> actual = HashMap.of("key", "value");

assertThat(actual).containsOnlyKeys("key");
}

@Test
void should_fail_when_Map_is_null() {
assertThatThrownBy(
() -> assertThat((Map<String, String>) null).containsOnlyKeys("key")
)
.isInstanceOf(AssertionError.class)
.hasMessage(shouldNotBeNull().create());
}

@Test
void should_fail_if_keys_parameter_is_null() {
final Map<String, String> actual = HashMap.of("key", "value");

assertThatThrownBy(
() -> assertThat(actual).containsOnlyKeys((String[]) null)
)
.isInstanceOf(NullPointerException.class)
.hasMessage("The array of keys to look for should not be null");
}

@Test
void should_fail_if_keys_parameter_is_empty() {
final Map<String, String> actual = HashMap.of("key", "value");
final String[] keys = new String[0];

assertThatThrownBy(
() -> assertThat(actual).containsOnlyKeys(keys)
)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The array of keys to look for should not be empty");
}

@Test
void should_fail_if_Map_contains_more_than_given_keys() {
final Map<String, String> actual = HashMap.of("key-1", "value-1", "key-2", "value-2");

assertThatThrownBy(
() -> assertThat(actual).containsOnlyKeys("key-1")
)
.isInstanceOf(AssertionError.class)
.hasMessage(
"\n" +
"Expecting:\n" +
" <HashMap((key-1, value-1), (key-2, value-2))>\n" +
"to contain only following keys:\n" +
" <HashSet(key-1)>\n" +
"keys not found:\n" +
" <HashSet()>\n" +
"and keys not expected:\n" +
" <HashSet(key-2)>\n"
);
}

@Test
void should_fail_if_Map_has_same_size_but_contains_different_keys() {
final Map<String, String> actual = HashMap.of("key-1", "value-1", "key-2", "value-2");

assertThatThrownBy(
() -> assertThat(actual).containsOnlyKeys("key-1", "key-3")
)
.isInstanceOf(AssertionError.class)
.hasMessage(
"\n" +
"Expecting:\n" +
" <HashMap((key-1, value-1), (key-2, value-2))>\n" +
"to contain only following keys:\n" +
" <HashSet(key-1, key-3)>\n" +
"keys not found:\n" +
" <HashSet(key-3)>\n" +
"and keys not expected:\n" +
" <HashSet(key-2)>\n"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,70 @@
* Copyright 2012-2019 the original author or authors.
*/

import org.junit.jupiter.api.Test;

import io.vavr.Tuple2;
import io.vavr.collection.HashMap;
import io.vavr.collection.List;
import io.vavr.collection.Map;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.error.ShouldNotBeNull.shouldNotBeNull;
import static org.assertj.vavr.api.VavrAssertions.assertThat;

class MapAssert_containsOnly_Test {

@Test
void should_pass_if_Map_contains_only_given_entry() {
void should_pass_if_Map_contains_only_given_entries() {
final Map<String, String> actual = HashMap.of("key", "value");

assertThat(actual).containsOnly(List.of(Map.entry("key", "value")));
}

@Test
void should_shrug() {
void should_fail_when_Map_is_null() {
assertThatThrownBy(
() -> assertThat((Map<String, String>) null).containsOnly(List.of(Map.entry("key", "value")))
)
.isInstanceOf(AssertionError.class)
.hasMessage(shouldNotBeNull().create());
}

@Test
void should_fail_if_entries_parameter_is_null() {
final Map<String, String> actual = HashMap.of("key", "value");

assertThatThrownBy(
() -> assertThat(actual).containsOnly(null)
() -> assertThat(actual).containsOnly(null)
)
.isInstanceOf(AssertionError.class)
.hasMessage("Expected entries should not be null");
.isInstanceOf(NullPointerException.class)
.hasMessage("The entries to look for should not be null");
}

@Test
void should_fail_if_entries_parameter_is_empty_but_actual_Map_is_not() {
final Map<String, String> actual = HashMap.of("key", "value");
final Iterable<Tuple2<String, String>> entries = List.empty();

assertThatThrownBy(
() -> assertThat(actual).containsOnly(entries)
)
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("The entries to look for should not be empty");
}

@Test
void should_fail_if_one_of_entries_is_null() {
final Map<String, String> actual = HashMap.of("key", "value");
final List<Tuple2<String, String>> entries = List.empty();

assertThatThrownBy(
() -> assertThat(actual).containsOnly(entries.append(null))
)
.isInstanceOf(NullPointerException.class);
}

@Test
void should_fail_if_Map_contains_more_than_given_entry() {
void should_fail_if_Map_contains_more_than_given_entries() {
final Map<String, String> actual = HashMap.of("key-1", "value-1", "key-2", "value-2");

assertThatThrownBy(
Expand Down

0 comments on commit 4627e2c

Please sign in to comment.