Assert number of matching elements in collection via Hamcrest - java

I have a collection of matchers like List<Matcher<?>> filters and some collection of elements List<Element> elementsToCheck. I want to create an assertion that checks if there are x elements that match all filters, something like that:
public void checkMatch(List<Matcher<?>> filters, int expectedSize){
MatcherAssert.assertThat(elementsToCheck, ???);
}
I wrote something like that:
final Iterator<Element> iterator = this.elements.iterator();
final List<Element> filtered = new ArrayList<>();
while (iterator.hasNext()) {
final Element element = iterator.next();
boolean allMatches = true;
for (final Matcher<?> matcher : this.filters) {
if (!matcher.matches(element)) {
allMatches = false;
break;
}
}
if (allMatches) {
filtered.add(element);
}
}
MatcherAssert.assertThat(filtered,
Matchers.hasSize(this.expectedSize));
Is there any better solution?

org.hamcrest.CoreMatchers.allOf matcher can be used instead of the list of matchers. Then a test may look as follows (I test list of Strings as an example):
// given
Matcher<String> allOfMatcher = allOf(containsString("a"), containsString("b"));
long expectedNumberOfMatches = 2L;
// when
List<String> elementsToCheck = Arrays.asList("aa", "ab", "ba", "bb"); // substitute with some actual method call
// then
assertThat(elementsToCheck, notNullValue());
assertThat(elementsToCheck.stream().filter(allOfMatcher::matches).collect(Collectors.counting()), equalTo(expectedNumberOfMatches));
You can even pass the already existing list of matchers to overloaded version of allOf that takes Iterable as an argument.
private Matcher<Element> getAllOfMatcher(List<Matcher<? super Element>> matchers) {
return CoreMatchers.allOf(matchers);
}

If I understodd task right:
List elementsToCheck- collection of elements
this.filters - collection of Matchers
elementsToCheck.stream()
.filter(element ->!this.filters.stream()
.filter(matcher -> matcher.matches(element))
.collect(Collectors.toList()).size() == this.filters.size())
.collect(Collectors.toList()).size() == this.expectedSize

Related

Unable to get my head around Predicate isEqual method

In Java docs it is given -
Modifier and Type Method and Description
static <T> Predicate<T> isEqual(Object targetRef)
Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).
In https://www.geeksforgeeks.org/java-8-predicate-with-examples/
it is given -
isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal according to Objects.equals(Object, Object).
static Predicate isEqual(Object targetRef)
Returns a predicate that tests if two arguments are
equal according to Objects.equals(Object, Object).
T : the type of arguments to the predicate
Parameters:
targetRef : the object reference with which to
compare for equality, which may be null
Returns: a predicate that tests if two arguments
are equal according to Objects.equals(Object, Object)
I can't get a grisp of what this Objects.equals(Object, Object) might be
I write the following code to try it out -
Class Fruits -
Fruits.java -
public class Fruits {
private String fruit;
public Fruits(String fruit) {
this.fruit = fruit;
}
public String getFruit() {
return fruit;
}
}
Here, the other methods of predicate seem to be quite easy to understand -
Predicate<List<Fruits>> containsApple = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Apple")) {
myReturn = true;
break;
}
}
return myReturn;
};
Predicate<List<Fruits>> containsOrange = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Orange")) {
myReturn = true;
break;
}
}
return myReturn;
};
Predicate<List<Fruits>> containsAppleAndOrange = list -> {
return containsApple.and(containsOrange).test(list);
};
Predicate<List<Fruits>> containsAppleOrRange = list -> {
return containsApple.or(containsOrange).test(list);
};
Predicate<List<Fruits>> notContainsApple = list -> {
return containsApple.negate().test(list);
};
Predicate<List<Fruits>> notContainsOrange = list -> {
return containsOrange.negate().test(list);
};
Predicate<List<Fruits>> notContainsAppleAndOrange = list -> {
return containsAppleAndOrange.negate().test(list);
};
Predicate<List<Fruits>> notContainsAppleOrOrange = list -> {
return containsAppleOrRange.negate().test(list);
};
Here I test it with following data -
List<Fruits> list1 = new ArrayList<>(List.of(
new Fruits("Apple"),
new Fruits("Orange"),
new Fruits("Mango"),
new Fruits("Banana")
));
List<Fruits> list2 = new ArrayList<>(List.of(
new Fruits("Apple"),
new Fruits("Mango"),
new Fruits("Banana"),
new Fruits("Berry")
));
List<Fruits> list3 = new ArrayList<>(List.of(
new Fruits("Orange"),
new Fruits("Mango"),
new Fruits("Banana"),
new Fruits("Berry")
));
Result is as expected.
But in no way can I understand how to implement the isEqual() method -
To see that two arguments are equal are not I create another predicate -
redicate<List<Fruits>> containsApple2 = list -> {
boolean myReturn = false;
Iterator<Fruits> iterator = list.iterator();
while (iterator.hasNext()) {
Fruits fruits = iterator.next();
String fruit = fruits.getFruit();
if (fruit.equals("Apple")) {
myReturn = true;
break;
}
}
return myReturn;
};
I try something like (without understanding why) -
System.out.println(Predicate.isEqual(containsApple).test(list1));
Output - false
Now what happened here?
System.out.println(Predicate.isEqual(containsApple2).test(containsApple));
Output - false
Now again what happened here?
So, how to exactly use this isEqual method?
Predicate.isEqual is a factory method that creates predicates that test if a given thing is equal to the parameter passed in.
Predicate.isEqual(containsApple) creates a Predicate<Predicate<List<Fruits>>> that tests if a given thing is equal to containsApple. However, since containsApple refers to an instance created from a lambda, and nothing much is guaranteed about the equality of instances created from lambda expressions (See the JLS), nothing much can be said about the result of calling test on it. The classes of the lambda instances may or may not implement equals, and containsApple may or may not be the same instance as containsApple2, depending on the implementation.
Rather than comparing lambda instances, a typical example of using Predicate.isEqual is:
Fruits apple = new Fruits("Apple");
Predicate<Fruits> isApple = Predicate.isEqual(apple);
// rather than this slightly longer version:
// Predicate<Fruits> isApple = x -> Objects.equals(x, apple);
Then you can pass isApple around, to other methods that take Predicates, and/or call test on it. isApple.test(apple) would be true, isApple.test(new Fruits("something else")) would be false. I would also recommend that you override equals and hashCode in Fruits.
Note that we generally make predicates that test against individual objects, rather than lists (collections) of things. We would pass these predicates to other methods (such as Stream.filter), and let them do the filtering. For example, to filter a list to get all the apples:
List<Fruits> apples = fruitsList.stream()
.filter(Predicate.isEqual(apple)).toList();
One should use singular here for the class Fruits.
First you must establish equality of Fruit. Also should you ever want it to store in a HashMap or HashSet, a hashCode implementation is important.
public class Fruit {
private final String fruit; // Or name.
public Fruit(String fruit) {
this.fruit = fruit;
}
public String getFruit() {
return fruit;
}
#Override
public boolean equals(Object other) {
return other instanceOf Fruit && ((Fruit) other).fruit.equals(fruit);
}
#Override
public int hashCode() {
return fruit.hashCode();
}
}
The Iterator class is rather old and its primary advantage is you can walk through and still remove an element with iterator.remove(), which is not allowed on the List in a - statefull - for (ConcurrentModificationException).
Predicate<List<Fruit>> containsApple = list -> {
for (Fruit fruit: list) {
if (fruit.getFruit().equals("Apple")) {
return true;
}
}
return false;
};
Predicate<List<Fruit>> containsApple = list -> list.contains(new Fruit("Apple"));
Advisable is to get acquainted with Stream (like for iterating through a collection) and its expressive power.
Predicate<List<Fruit>> containsApple = list ->
list.stream()
.anyMatch(fr -> fr.getFruit().equals("Apple"));
As mentioned by #user16320675 in comments one of the simplest examples would be -
import java.util.function.Predicate;
public class App {
public static void main(String[] args) {
Integer num1 = 2;
Integer num2 = 3;
Predicate<Integer> predicate = Predicate.isEqual(num1);
System.out.println(predicate.test(num1));
System.out.println(predicate.test(num2));
}
}
Output -
true
false
The code can also be rewritten as -
System.out.println(Predicate.isEqual(num1).test(num1));
System.out.println(Predicate.isEqual(num1).test(num2));
with same output.
A practical application in Java streams -
Code -
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class App {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Elephant");
list.add("Hippo");
list.add("Rhino");
list.add("Deer");
list.add("Hippo");
list.add("Zebra");
Predicate<String> predicate = Predicate.isEqual("Hippo");
list.stream().filter(predicate).forEach(System.out::println);
}
}
Output -
Hippo
Hippo

Reduce repeated elements in a list

To compact in a new list without repeated elements, there may be null elements. I need help .
I have this error "Tester Error (Individual Delivery 4): the method returns []instead of [1] when invoked with [1]".
public <E> PositionList<E> compactar (Iterable<E> lista)
{
if(lista == null){
throw new IllegalArgumentException();
}// if
PositionList<E> newLista = new NodePositionList<E>();
Iterator<E>iterator = lista.iterator();
while(iterator.hasNext())
{
if(eqNull(iterator,iterator.next())) {
newLista.addLast(iterator.next());
}//if
}//while
return newLista;
}//compactar
//-------------assistant--------------------------------------------------------------
public static boolean eqNull (Object o1, Object o2)
{
return o1 == o2 || o1!= null && o1.equals(o2);
}// de eqNUll
}// Operacioncompactar
Not clear if you want to remove all dupes or just remove nulls. These remove dupes.
List<Comparable> l = ...; // The source list
List<Comparable> nl = new ArrayList<>(); // New list without dupes
Collections.sort(l);
Comparable last = UUIDs.randomUUID().toString(); // This one will never be in our source list
for (Comparable c: l) {
if (!Objects.equal(c, last)) { // Or some other null-safe equals function
nl.add(c);
}
last = c;
}
Running time O(nlogn). Elements in list of course need to implement a sensible equals() and hashCode().
Set<?> set = new HashSet<String>(); // Track "seen"
List<?> l = ...; // Original list
List<?> nl = new ArrayList<>(); // New list without dupes
for (Object o: l) {
if (!set.contains(o)) {
nl.add(o);
}
set.add(o);
}
Running time is O(n), since hashset is constant lookup time. Or simpler:
Set<?> set = new HashSet<String>(); // Will be collection without dupes
List<?> l = ...; // Original list
for (Object o: l) {
set.add(o); // Rely on set semantics to remove dupes
}
List<?> nl = new ArrayList<>(set);
Of course the objects in the list must implement a sensible equals() and hashCode().
With java 8, you can use Stream distinct to solve that.
The sample code as below. Hope it will help you.
// input data
List<String> a = new ArrayList<>();
a.add("A");
a.add("A");
a.add("A");
a.add(null);
a.add(null);
Iterator source = a.iterator();
Iterable<String> iterable = () -> source;
// logic code
Iterator temp = StreamSupport
.stream(iterable.spliterator(), false)
.distinct()
.collect(Collectors.toList()).iterator();
Iterable result = () -> temp;
// verify result
StreamSupport
.stream(result.spliterator(), false)
.forEach(System.out::println)
;

Assert List<List<String>> contains List<String> with no order

I have a List<List<String>> with sample data like:
("T1#R1", "T1#R1", "T1#R3", "T1#R4")
("T1#R1", "T1#R1", "T1#R3", "T1#R5")
("T1#R1", "T1#R1", "T1#R6", "T1#R4")
("T1#R1", "T1#R1", "T1#R6", "T1#R5")
And I need to assert, that a List<String> is present in the above sample, but without taking order into consideration.
For example, the following list ("T1#R1", "T1#R1", "T1#R4", "T1#R3") should be considered as present in the List<List<String>>, as it would contain the same items as the 1st list, but in different order.
On the other hand, ("T1#R1", "T1#R3", "T1#R4", "T1#R3") shouldn't be considered as present in the list, as it has the same items, but with a different count.
I know I could do this programmatically, but was wandering if there could be a Matcher for example that could help.
I've seen assertions like:
assertThat(myList, containsInAnyOrder(anotherList.toArray())
But that would just compare one list with another, and not a list inside a List of Lists.
PS: I'm using Java6, hamcrest-core-1.3, testng-5.14.1
I don't know of any matcher that can do what you want, so I'm afraid you'll have to program it.
I would simply sort the target list and then I'd iterate the sublists until a match is found:
List<String> target = new ArrayList<>(anotherList);
target.sort();
boolean result = myList.stream()
.anyMatch(sublist -> equalsInAnyOrder(sublist, target));
Where method equalsInAnyOrder would be as follows:
public <T> boolean equalsInAnyOrder(List<T> sublist, List<T> target) {
List<String> copy = new ArrayList<>(sublist);
copy.sort();
return copy.equals(target);
}
This sorts each sublist and compares it with the target sorted list, so it's not performance-wise, but at least it's simple and succint code.
EDIT as per OP's need to target Java 6:
The logic is exactly the same as in the Java 8 version. First sort the target list and then compare each sublist until a match is found:
List<String> target = new ArrayList<>(anotherList);
Collections.sort(target);
The stream() with anyMatch has now become a while loop:
boolean match = false;
Iterator<List<String>> it = myList.iterator();
while (it.hasNext() && !match) {
List<String> sublist = it.next();
match = equalsInAnyOrder(sublist, target);
}
And now method equalsInAnyOrder looks like this:
public <T> boolean equalsInAnyOrder(List<T> sublist, List<T> target) {
List<String> copy = new ArrayList<>(sublist);
Collections.sort(copy);
return copy.equals(target);
}
I don't get a one-line-solution but my tests passes.
I iterate through the list of lists, wrapping each list to a map (entry is the key, count the value) as well as for the list to check. Now I can check for equality:
public void listOfLists() throws Exception {
List<List<String>> myList = Arrays.asList(
Arrays.asList("T1#R1", "T1#R1", "T1#R3", "T1#R4"),
Arrays.asList("T1#R1", "T1#R1", "T1#R3", "T1#R5"),
Arrays.asList("T1#R1", "T1#R1", "T1#R6", "T1#R4"),
Arrays.asList("T1#R1", "T1#R1", "T1#R6", "T1#R5"));
List<String> easy = Arrays.asList("T1#R1", "T1#R1", "T1#R4", "T1#R3");
List<String> duplicate = Arrays.asList("T1#R1", "T1#R5", "T1#R1", "T1#R6");
List<String> noMatch = Arrays.asList("T1#R1", "T1#R5", "T1#R6");
Map<String, Integer> easyCount = countEntries(easy);
Map<String, Integer> duplicateCount = countEntries(duplicate);
Map<String, Integer> noCount = countEntries(noMatch);
for (List<String> l : myList) {
Map<String, Integer> countedEntries = countEntries(l);
if (countedEntries.equals(easyCount)) {
System.out.println("easy matches");
}
if (countedEntries.equals(duplicateCount)) {
System.out.println("duplicate matches");
}
if (countedEntries.equals(noCount)) {
System.out.println("Damn!");
}
}
}
private Map<String, Integer> countEntries(List<String> original) {
return original.stream()
.collect(Collectors.toMap(Function.identity(), s -> 1, Integer::sum));
}
This prints
easy matches
duplicate matches
I don't know any Matcher that does that, do you care about dupiclates or not? (will you have duplicate values in your strings?)
I would go for somthing like that:
private boolean containsInAnyOrder(List<List<String>> container, List<String> list)
{
for (List<String> list1 : container)
{
if(list.size()==list1.size())
{
if(list1.containsAll(list))
{
return true;
}
}
}
return false;
}
This would work only if you don't care about duplicate elements and there count.
("T1#R1", "T1#R1", "T1#R1", "T1#R2")
("T1#R1", "T1#R2", "T1#R2", "T1#R1")
would return true for example. Would you have duplicates? (same for Set solution, it would not work for the same reason)
In case of duplicates you need to count each items:
private boolean containsInAnyOrder(List<List<String>> container, List<String> list)
{
for (List<String> list1 : container)
{
if(list.size()==list1.size())
{
boolean found = true;
for(String string : list)
{
if (list.stream().filter(pS -> pS.equals(string)).count() != list1.stream().filter(pS -> pS.equals(string)).count())
{
found = false;
}
}
if(found)
{
return true;
}
}
}
return false;
}
Note that it's not optimised, inner for loop could be stop before in case of mismatch.

Assert that one of string in array contains substring

List<String> expectedStrings = Arrays.asList("link1", "link2");
List<String> strings = Arrays.asList("lalala link1 lalalla", "lalalal link2 lalalla");
For each expectedString, I need assert that any of string in the 'strings' contains expectedString.
How I may assert this with Hamcrest?
Thanks for your attention.
Update
After checking this old answer, I found that you can use a better combination of built-in matchers making both the assertion and the error messages more readable:
expectedStrings.forEach(expectedString ->
assertThat(strings, hasItem(containsString(expectedString))));
Original answer for reference
You can do it quite easily with streams:
assertThat(expectedStrings.stream().allMatch(
expectedString -> strings.stream()
.anyMatch(string -> string.contains(expectedString))),
is(true));
allMatch will make sure all of the expectedStrings will be checked, and with using anyMatch on strings you can efficiently check if any of the strings contains the expected string.
At the moment there isn't any matcher in hamcrest with this requeriment, despite you can combine multiple this is not possible yet.
So, in cases like yours the best solution in my opinion is to create your own matcher Why?
It can be reused
Is maintainable
Is more readable
So in your case you need to match the first list contains any string of the second one, you can create a Matcher like next:
public class ContainsStringsOf extends BaseMatcher<List<String>> {
private final List<String> valuesToCompare;
public ContainsStringsOf(List<String> valuesToCompare) {
this.valuesToCompare = valuesToCompare;
}
#Override
public void describeTo(Description description) {
description.appendText("doesn't contains all of " + valuesToCompare.toString() + " text");
}
#Override
public boolean matches(Object o) {
List<String> values = (List<String>) o;
for (String valueToCompare : valuesToCompare) {
boolean containsText = false;
for (String value : values) {
if (value.contains(valueToCompare)) {
containsText = true;
}
}
if (!containsText) {
return false;
}
}
return true;
//note: you can replace this impl with java-8 #florian answer comparison
//return valuesToCompare.stream().allMatch(exp -> strings.stream().anyMatch(st-> st.contains(exp)))
}
#Factory
public static Matcher<List<String>> containsStringsOf(List<String> collection) {
return new ContainsStringsOf(collection);
}
}
Then you can use it is just as hamcrest matcher is used:
List<String> expectedStrings = Arrays.asList("link1", "link2");
List<String> strings = Arrays.asList("lalala link1 lalalla", "lalalal link2 lalalla");
Assert.assertThat(strings , containsStringsOf(expectedStrings));

Get an element through an iterable string (guava)

I have an Iterable string (guava library). How can I get elements from it. Here is my code:
public static String hillcipher(String str)
{
String hillcipher="";
Iterable<String> pieces = null;
for (int i=0; i<=str.length()-1; i++){
char c = str.charAt(i);
if (Character.isLetter(c)){
pieces = Splitter.fixedLength(2).split(str);
}
}
System.out.println(pieces);
return hillcipher;
here i split a string into pieces of 2 chars each. for example "java" wil be splided to "ja", "va". But then i want to get each character separatly just to do other calculations on them.
There are various ways to get an element from an iterable:
Iterate over each element:
for (String piece : pieces) {
// do something
}
or
Iterator<String> iterator = pieces.iterator();
while (iterator.hasNext()) {
String piece = iterator.next();
// do something
}
etc.
iterating through just the first N elements you want if present:
Iterator<String> iterator = pieces.iterator();
if (iterator.hasNext()) {
String firstPiece = iterator.next();
// do something
if (iterator.hasNext()) {
String secondPiece = iterator.next();
// do something else
// etc.
}
}
using helper functions like those in Guava's Iterables:
String thirdPiece = Iterables.get(pieces, 2);
or
String lastPieceOrEmpty = Iterables.getLast(pieces, "");
etc.
However, if you'd like to simply access the elements like you would a list you can use Splitter.splitToList(CharSequence) instead. It is the same as Splitter.split(CharSequence) but instead of returning a potentially lazy evaluated Iterable it returns a populated ImmutableList which supports random access to its elements.

Categories

Resources