JavaHamcrest icon indicating copy to clipboard operation
JavaHamcrest copied to clipboard

containsInAnyOrder incorrectly identifies differences in identical collections

Open luskentyre-green opened this issue 4 years ago • 1 comments

When comparing two Lists or sets of characters, containsInOrder will report that a character is missing even when they sets or lists contain the same elements.

Code to reproduce: (hamcrest 2.2 plus JUnit 5)

package hamcrest.test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;

class HamcrestTest {
  @Test
  void testTwoIdenticalSets() {
    Set<Character> testSetOne = new HashSet<>(Arrays.asList('!', '$', '-', '=', '+', '*'));
    Set<Character> testSetTwo = new HashSet<>(testSetOne);

    assertThat(testSetOne.containsAll(testSetTwo), is(true));
    // This assertion will fail, claiming that testSetOne does not contain '!'
    assertThat(testSetOne, containsInAnyOrder(testSetTwo));
   }

  @Test
  void testTwoIdenticalLists() {
    List<Character> testSetOne = new ArrayList<>(Arrays.asList('%', '$', '-', '=', '+', '*'));
    List<Character> testSetTwo = new ArrayList<>(testSetOne);

    assertThat(testSetOne.containsAll(testSetTwo), is(true));
    // This assertion will fail, claiming that testSetOne does not contain '%'
    assertThat(testSetOne, containsInAnyOrder(testSetTwo));
  }

}

output:

java.lang.AssertionError: 
Expected: iterable with items [<[!, $, *, +, -, =]>] in any order
     but: not matched: "!"
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:6)

java.lang.AssertionError: 
Expected: iterable with items [<[%, $, -, =, +, *]>] in any order
     but: not matched: "%"
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:6)

luskentyre-green avatar Nov 17 '21 12:11 luskentyre-green

I suspect this is because there is no containsInAnyOrder(..) accepting a collection of the actual items to match, but there is an overload accepting a collection with matchers for every element which needs to match.

So e.g. in the example with the sets, you are in fact asserting that testSetOne must contain exactly one element, and that single element should be testSetTwo. The code is invoking the T ... vararg overload with one argument.

runeflobakk avatar Mar 08 '22 21:03 runeflobakk