Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MapAssert.containsOnlyKeys #63

Merged
merged 2 commits into from
Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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