All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.assertj.vavr.internal.Multimaps Maven / Gradle / Ivy

There is a newer version: 0.4.3
Show newest version
/*
 * 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.
 *
 * Copyright 2017-2020 the original author or authors.
 */
package org.assertj.vavr.internal;

import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.collection.*;
import io.vavr.control.Option;
import org.assertj.core.api.AssertionInfo;
import org.assertj.core.api.Condition;
import org.assertj.core.internal.Conditions;
import org.assertj.core.internal.Failures;
import org.assertj.core.internal.Objects;

import java.util.function.Predicate;

import static io.vavr.Predicates.not;
import static org.assertj.core.error.ElementsShouldBe.elementsShouldBe;
import static org.assertj.core.error.ShouldContain.shouldContain;
import static org.assertj.core.error.ShouldContainAnyOf.shouldContainAnyOf;
import static org.assertj.core.error.ShouldContainExactly.elementsDifferAtIndex;
import static org.assertj.core.error.ShouldContainExactly.shouldContainExactly;
import static org.assertj.core.error.ShouldContainKeys.shouldContainKeys;
import static org.assertj.core.error.ShouldContainOnly.shouldContainOnly;
import static org.assertj.core.error.ShouldContainOnlyKeys.shouldContainOnlyKeys;
import static org.assertj.core.error.ShouldContainValue.shouldContainValue;
import static org.assertj.core.error.ShouldContainValues.shouldContainValues;
import static org.assertj.core.error.ShouldNotContain.shouldNotContain;
import static org.assertj.core.error.ShouldNotContainKeys.shouldNotContainKeys;
import static org.assertj.core.error.ShouldNotContainValue.shouldNotContainValue;
import static org.assertj.core.internal.Arrays.assertIsArray;
import static org.assertj.core.internal.CommonValidations.failIfEmptySinceActualIsNotEmpty;
import static org.assertj.core.internal.CommonValidations.hasSameSizeAsCheck;
import static org.assertj.core.util.Objects.areEqual;
import static org.assertj.core.util.Preconditions.checkArgument;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.vavr.api.ShouldNotContainValues.shouldNotContainValues;

public final class Multimaps {

    private static final Multimaps INSTANCE = new Multimaps();

    private Failures failures = Failures.instance();

    private Conditions conditions = Conditions.instance();

    private Multimaps() {
    }

    public static Multimaps instance() {
        return INSTANCE;
    }

    /**
     * Verifies that the given {@code Multimap} contains the value for given {@code key} that satisfy given {@code valueCondition}.
     *
     * @param             key type
     * @param             value type
     * @param info           contains information about the assertion
     * @param actual         the given {@code Multimap}
     * @param key            the given key to check
     * @param valueCondition the given condition for check value
     * @throws NullPointerException if the given values is {@code null}
     * @throws AssertionError       if the actual map is {@code null}
     * @throws AssertionError       if the actual map does not contain the given {@code key}
     * @throws AssertionError       if the actual map contains the given key, but value does not match the given {@code valueCondition}
     */
    @SuppressWarnings("unchecked")
    public  void assertHasEntrySatisfying(AssertionInfo info, Multimap actual, K key,
                                                Condition valueCondition) {
        conditions.assertIsNotNull(valueCondition);
        assertContainsKeys(info, actual, key);
        Option> value = actual.get(key);
        value
                .getOrElse(List.empty())
                .filter(valueCondition::matches)
                .getOrElseThrow(() -> failures.failure(info, elementsShouldBe(actual, value, valueCondition)));
    }

    public  void assertContainsAnyOf(AssertionInfo info, Multimap actual,
                                           Tuple2[] entries) {
        doCommonContainsCheck(info, actual, entries);
        if (actual.isEmpty() && entries.length == 0) return;
        failIfEmptySinceActualIsNotEmpty(entries);
        for (Tuple2 entry : entries) {
            if (containsEntry(actual, entry)) return;
        }
        throw failures.failure(info, shouldContainAnyOf(actual, entries));
    }

    /**
     * Asserts that the given {@code Multimap} contains the given entries, in any order.
     *
     * @param      key type
     * @param      value type
     * @param info    contains information about the assertion
     * @param actual  the given {@code Multimap}
     * @param entries the entries that are expected to be in the given {@code Multimap}
     * @throws NullPointerException     if the array of entries is {@code null}
     * @throws IllegalArgumentException 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 Multimap} is {@code null}
     * @throws AssertionError           if the given {@code Multimap} does not contain the given entries
     */
    public  void assertContains(AssertionInfo info, Multimap actual,
                                      Tuple2[] entries) {
        doCommonContainsCheck(info, actual, entries);
        if (actual.isEmpty() && entries.length == 0) return;
        failIfEmptySinceActualIsNotEmpty(entries);
        final Set> notFound = Array.of(entries).filter(entryNotPresentIn(actual)).toSet();
        if (isNotEmpty(notFound)) {
            throw failures.failure(info, shouldContain(actual, entries, notFound));
        }
    }

    /**
     * Asserts that the given {@code Multimap} contains the given entries only.
     *
     * @param      key type
     * @param      value type
     * @param info    contains information about the assertion
     * @param actual  the given {@code Multimap}
     * @param entries the entries that are expected to only be in the given {@code Multimap}
     * @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 Multimap} is {@code null}
     * @throws AssertionError       if the given {@code Multimap} contains any of the given entries
     */
    public  void assertContainsOnly(AssertionInfo info, Multimap actual, Iterable> entries) {
        assertNotNull(info, actual);
        failIfNull(entries);
        if (actual.isEmpty() && !entries.iterator().hasNext()) return;
        failIfEmpty(entries);
        Multimap expected = HashMultimap.withSeq().ofEntries(entries);
        Multimap notExpected = actual.filter(entryNotPresentIn(expected));
        if (isNotEmpty(notExpected)) {
            Multimap notFound = expected.filter(entryNotPresentIn(actual));
            throw failures.failure(info, shouldContainOnly(actual, expected, notFound, notExpected));
        }
    }


    /**
     * Verifies that the actual {@code Multimap} contains only the given entries and nothing else, in order.
* This assertion should only be used with {@code Multimap} that have a consistent iteration order (i.e. don't use it with * {@link io.vavr.collection.HashMultimap}). * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param entries the given entries * @throws NullPointerException if the given entries array is {@code null} * @throws AssertionError if the actual map is {@code null} * @throws IllegalArgumentException if the given entries array is empty * @throws AssertionError if the actual {@code Multimap} does not contain the given entries with same order, i.e. the actual {@code Multimap} * contains some or none of the given entries, or the actual {@code Multimap} contains more entries than the given ones * or entries are the same but the order is not */ public void assertContainsExactly(AssertionInfo info, Multimap actual, @SuppressWarnings("unchecked") Tuple2... entries) { doCommonContainsCheck(info, actual, entries); if (actual.isEmpty() && entries.length == 0) return; failIfEmpty(entries); assertHasSameSizeAs(info, actual, entries); final Multimap expectedEntries = asLinkedMultimap(entries); final Multimap notExpected = actual.filter(entry -> !expectedEntries.contains(entry)); final Multimap notFound = expectedEntries.filter(entry -> !actual.contains(entry)); if (notExpected.isEmpty() && notFound.isEmpty()) { // check entries order int index = 0; for (K keyFromActual : actual.keySet()) { if (areNotEqual(keyFromActual, entries[index]._1)) { Tuple2> actualEntry = Tuple.of(keyFromActual, actual.get(keyFromActual).get()); throw failures.failure(info, elementsDifferAtIndex(actualEntry, entries[index], index)); } index++; } // all entries are in the same order. return; } throw failures.failure(info, shouldContainExactly(actual, List.of(entries), notFound, notExpected)); } /** * Asserts that the given {@code Multimap} does not contain the given entries. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param entries the entries that are expected to be in the given {@code Multimap} * @throws NullPointerException if the array of entries is {@code null} * @throws IllegalArgumentException 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 Multimap} is {@code null} * @throws AssertionError if the given {@code Multimap} contains any of the given entries */ public void assertDoesNotContain(AssertionInfo info, Multimap actual, Tuple2[] entries) { failIfNullOrEmpty(entries); assertNotNull(info, actual); failIfEmptySinceActualIsNotEmpty(entries); final Set> found = Array.of(entries).filter(actual::contains).toSet(); if (isNotEmpty(found)) { throw failures.failure(info, shouldNotContain(actual, entries, found)); } } /** * Verifies that the actual {@code Multimap} contains the given keys. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param keys the given keys * @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 Multimap} is {@code null} * @throws AssertionError if the given {@code Multimap} does not contain the given keys */ public void assertContainsKeys(AssertionInfo info, Multimap actual, @SuppressWarnings("unchecked") K... keys) { doCommonContainsCheck(info, actual, keys); if (doCommonEmptinessChecks(actual, keys)) return; Set expected = HashSet.of(keys); Set notFound = expected.filter(keyNotPresentIn(actual.keySet())); if (isNotEmpty(notFound)) { throw failures.failure(info, shouldContainKeys(actual, notFound.toJavaSet())); } } /** * Asserts that the given {@code Multimap} contains the given keys, in any order. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param keys the keys that are expected to be in the given {@code Multimap} * @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 Multimap} is {@code null} * @throws AssertionError if the given {@code Multimap} does not contain the given keys */ public void assertContainsOnlyKeys(AssertionInfo info, Multimap actual, K[] keys) { doCommonContainsCheck(info, actual, keys); if (doCommonEmptinessChecks(actual, keys)) return; Set expected = HashSet.of(keys); Set notExpected = actual.keySet().filter(keyNotPresentIn(expected)); if (isNotEmpty(notExpected)) { Set notFound = expected.filter(keyNotPresentIn(actual.keySet())); throw failures.failure(info, shouldContainOnlyKeys(actual, expected, notFound, notExpected)); } } /** * Verifies that the actual {@code Multimap} does not contain the given keys. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param keys the given keys * @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 Multimap} is {@code null} * @throws AssertionError if the given {@code Multimap} contains the given keys */ public void assertDoesNotContainKeys(AssertionInfo info, Multimap actual, @SuppressWarnings("unchecked") K... keys) { doCommonContainsCheck(info, actual, keys); if (doCommonEmptinessChecks(actual, keys)) return; Set expected = HashSet.of(keys); Set found = expected.filter(keyPresentIn(actual.keySet())); if (isNotEmpty(found)) { throw failures.failure(info, shouldNotContainKeys(actual, found.toJavaSet())); } } /** * Verifies that the actual {@code Multimap} contains the given value. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param value the given value * @throws AssertionError if the actual {@code Multimap} is {@code null} * @throws AssertionError if the actual {@code Multimap} does not contain the given value */ public void assertContainsValue(AssertionInfo info, Multimap actual, V value) { assertNotNull(info, actual); if (!actual.containsValue(value)) throw failures.failure(info, shouldContainValue(actual, value)); } /** * Verifies that the actual {@code Multimap} contains the given values. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param values the given values * @throws AssertionError if the actual {@code Multimap} is {@code null} * @throws AssertionError if the actual {@code Multimap} does not contain the given values * @throws NullPointerException if values vararg is {@code null} */ public void assertContainsValues(AssertionInfo info, Multimap actual, @SuppressWarnings("unchecked") V... values) { assertNotNull(info, actual); checkNotNull(values, "The array of values to look for should not be null"); if (actual.isEmpty() && values.length == 0) return; Set expected = HashSet.of(values); Set notFound = expected.filter(valueNotPresentIn(actual.values())); if (isNotEmpty(notFound)) throw failures.failure(info, shouldContainValues(actual, notFound.toJavaSet())); } /** * Verifies that the actual {@code Multimap} does not contain the given value. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param value the given value * @throws AssertionError if the actual {@code Multimap} is {@code null} * @throws AssertionError if the actual {@code Multimap} contains the given value */ public void assertDoesNotContainValue(AssertionInfo info, Multimap actual, V value) { assertNotNull(info, actual); if (actual.containsValue(value)) throw failures.failure(info, shouldNotContainValue(actual, value)); } /** * Verifies that the actual {@code Multimap} does not contain the given values. * * @param key type * @param value type * @param info contains information about the assertion * @param actual the given {@code Multimap} * @param values the given values * @throws AssertionError if the actual {@code Multimap} is {@code null} * @throws AssertionError if the actual {@code Multimap} contains the given values * @throws NullPointerException if values vararg is {@code null} */ public void assertDoesNotContainValues(AssertionInfo info, Multimap actual, @SuppressWarnings("unchecked") V... values) { assertNotNull(info, actual); checkNotNull(values, "The array of values to look for should not be null"); if (actual.isEmpty() && values.length == 0) return; Set expected = HashSet.of(values); Set found = expected.filter(valuePresentIn(actual.values())); if (isNotEmpty(found)) throw failures.failure(info, shouldNotContainValues(actual, found.toJavaSet())); } /** * Asserts that the number of entries in the given {@code Multimap} has the same size as the other array. * * @param info contains information about the assertion * @param multimap the given {@code Multimap} * @param other the group to compare * @throws AssertionError if the given {@code Multimap} is {@code null} * @throws AssertionError if the given array is {@code null} * @throws AssertionError if the number of entries in the given {@code Multimap} does not have the same size */ public void assertHasSameSizeAs(AssertionInfo info, Multimap multimap, Object other) { assertNotNull(info, multimap); assertIsArray(info, other); hasSameSizeAsCheck(info, multimap, other, multimap.size()); } private void doCommonContainsCheck(AssertionInfo info, Multimap actual, Tuple2[] entries) { assertNotNull(info, actual); failIfNull(entries); } private void doCommonContainsCheck(AssertionInfo info, Multimap actual, K[] keys) { assertNotNull(info, actual); failIfNull(keys); } private boolean doCommonEmptinessChecks(Multimap actual, K[] keys) { if (actual.isEmpty() && keys.length == 0) { return true; } failIfEmpty(keys); return false; } private static Multimap asLinkedMultimap(Tuple2[] entries) { if (entries.length != nonNullEntries(Array.of(entries)).length()) { throw new NullPointerException("One of expected entries is null"); } else { return LinkedHashMultimap.withSeq().ofEntries(entries); } } private static Traversable> nonNullEntries(Traversable> entries) { return entries.filter(java.util.Objects::nonNull); } private boolean containsEntry(Multimap actual, Tuple2 entry) { checkNotNull(entry, "Entry to look for should not be null"); return actual.containsKey(entry._1) && actual.get(entry._1).get().contains(entry._2); } private static boolean areNotEqual(K actualKey, K expectedKey) { return !areEqual(actualKey, expectedKey); } private static void failIfNullOrEmpty(Tuple2[] entries) { failIfNull(entries); failIfEmpty(entries); } private static void failIfNull(Iterable> entries) { checkNotNull(entries, "The entries should not be null"); } private static void failIfNull(K[] keys) { checkNotNull(keys, "The array of keys to look for should not be null"); } private static void failIfNull(Tuple2[] entries) { checkNotNull(entries, "The array of entries should not be null"); } private static void failIfEmpty(Iterable> entries) { checkArgument(entries.iterator().hasNext(), "The entries should not be empty"); } private static void failIfEmpty(Tuple2[] entries) { checkArgument(entries.length > 0, "The array of entries to look for should not be empty"); } private static void failIfEmpty(K[] keys) { checkArgument(keys.length > 0, "The array of keys to look for should not be empty"); } private static void assertNotNull(AssertionInfo info, Multimap actual) { Objects.instance().assertNotNull(info, actual); } private static Predicate> entryNotPresentIn(Multimap map) { return tuple -> !map.contains(tuple); } private static Predicate keyNotPresentIn(Set elements) { return not(keyPresentIn(elements)); } private static Predicate keyPresentIn(Set elements) { return elements::contains; } private static Predicate valueNotPresentIn(Traversable elements) { return not(valuePresentIn(elements)); } private static Predicate valuePresentIn(Traversable elements) { return elements::contains; } private static boolean isNotEmpty(Traversable traversable) { return !traversable.isEmpty(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy