Assertj-core: MapAssert::containsAllEntriesOf fails for non-empty actual and empty other map

Created on 17 Feb 2021  路  9Comments  路  Source: assertj/assertj-core

Summary

MapAssert::containsAllEntriesOf throws assertion error for non empty actual and empty other map:

java.lang.AssertionError: actual is not empty

    at org.assertj.core.internal.Maps.failIfEmptySinceActualIsNotEmpty(Maps.java:884)
    at org.assertj.core.internal.Maps.assertContains(Maps.java:350)
    at org.assertj.core.api.AbstractMapAssert.containsAllEntriesOf(AbstractMapAssert.java:580)
        // ...

Shouldn't this succeed as it does contain all 0 entries in the expected map? IMHO this would be more consistent with #2013 and non empty check should be explicit.

Example

Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
ringBearers.put(nenya, galadriel);
ringBearers.put(narya, gandalf);
ringBearers.put(vilya, elrond);
ringBearers.put(oneRing, frodo);

Map<Ring, TolkienCharacter> octopusRingBearers = new HashMap<>();

// java.lang.AssertionError: actual is not empty
assertThat(ringBearers).containsAllEntriesOf(octopusRingBearers);
breaking change improvement

All 9 comments

Thanks for reporting this, you have a point, we'll discuss this with the team before reaching a decision.

Team agrees to do it, moreover it's consistent with containsAll iterable assertion.

@aksh1618 keen to contribute it?

Sure @joel-costigliola, happy to :)

@joel-costigliola I've made the changes allowing empty values to pass for following methods:

contains(Map.Entry<? extends K, ? extends V>...聽entries)
containsAllEntriesOf(Map<? extends K, ? extends V> other)
containsAnyOf(Map.Entry<? extends K, ? extends V>...聽entries)

Am I correct in assuming the other two should also have similar behavior?

For contains and containsAnyOf, it is most likely a user error who has forgotten to pass value(s).
I mean why would anyone write assertThat(map).contains()? Some might even interpret that as containsNothing.

Better keep the current behavior for these assertions, on the other hand I agree we need to change containsAllEntriesOf since the other map could be empty.

@joel-costigliola Might be a bit extreme, but there could be cases where this won't be a user error, for instance:

Map<Ring, TolkienCharacter> ringBearers = new HashMap<>();
ringBearers.put(nenya, galadriel);
ringBearers.put(narya, gandalf);
ringBearers.put(vilya, elrond);
ringBearers.put(oneRing, frodo);

List<String> dwarveBearers = new ArrayList<>();
Map.Entry<Ring, TolkienCharacter>[] dwarvenRingBearers = 
        ringBearers.entrySet().stream().filter(entry -> dwarveBearers.contains(entry.getValue())).toArray(Map.Entry[]::new);

assertThat(ringBearers).contains(dwarvenRingBearers);

If such cases are to be considered too extreme for the scope of the library, should the absence of arguments throw an (IllegalArguments) exception in all cases and be documented as such?

For contains and containsAnyOf, it is most likely a user error who has forgotten to pass value(s).

I have to contradict myself on this one :facepalm:

Let's go with the same approach we followed for for iterable contains and containsAnyOf assertions, they fail if you pass an empty array and actual was not empty.

@joel-costigliola Added a PR

Was this page helpful?
0 / 5 - 0 ratings

Related issues

caugner picture caugner  路  4Comments

DavidOpDeBeeck picture DavidOpDeBeeck  路  3Comments

MikeShysh picture MikeShysh  路  3Comments

joel-costigliola picture joel-costigliola  路  6Comments

rdehuyss picture rdehuyss  路  5Comments