Assert that one of string in array contains substring
Asked Answered
B

3

7
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.

Bartle answered 24/1, 2017 at 12:24 Comment(1)
You will need to tell us what you have tried.Weidar
C
7

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.

Chronopher answered 24/1, 2017 at 12:36 Comment(1)
This is good. I realize now that I had made an incorrect inference and my answer was wrong. Well done.Madden
O
1

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));
Offoffbroadway answered 17/5, 2017 at 10:25 Comment(0)
H
0

I like the idea of a custom matcher. You could use the streams mechanism as the core of that. Here is a simple (inefficient) example:

 assertThat( infoLogs.stream().filter(logItem -> logItem.contains("writing out group")).collect(Collectors.toList()).size()).isNotZero();
Hovey answered 21/7, 2023 at 15:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.