Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.util.Optional matchers #421

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions hamcrest/src/main/java/org/hamcrest/Matchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import org.hamcrest.collection.ArrayMatching;
import org.hamcrest.core.IsIterableContaining;
import org.hamcrest.core.StringRegularExpression;
import org.hamcrest.optional.OptionalEmpty;
import org.hamcrest.optional.OptionalWithValue;
import org.hamcrest.text.IsEqualCompressingWhiteSpace;

import java.util.Optional;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -2184,4 +2187,45 @@ public static org.hamcrest.Matcher<org.w3c.dom.Node> hasXPath(java.lang.String x
return org.hamcrest.xml.HasXPath.hasXPath(xPath, namespaceContext);
}

/**
* Matcher that expects empty {@link Optional}.
*
* @param <T> type of optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> emptyOptional() {
return OptionalEmpty.emptyOptional();
}

/**
* Matcher for {@link Optional} that expects that value is present.
*
* @param <T> type of optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue() {
return OptionalWithValue.optionalWithValue();
}

/**
* Matcher for {@link Optional} that expects that value is present and is equal to <code>value</code>
*
* @param <T> type of optional value
* @param value to validate present optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue(T value) {
return OptionalWithValue.optionalWithValue(value);
}

/**
* Matcher for {@link Optional} that expects that value is present and matches <code>matcher</code>
*
* @param <T> type of optional value
* @param matcher matcher to validate present optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue(Matcher<? super T> matcher) {
return OptionalWithValue.optionalWithValue(matcher);
}
}
36 changes: 36 additions & 0 deletions hamcrest/src/main/java/org/hamcrest/optional/OptionalEmpty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.hamcrest.optional;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import java.util.Optional;

/**
* Matcher that expects empty {@link Optional}.

* @param <T> type of {@link Optional} value
*/
public class OptionalEmpty<T> extends TypeSafeDiagnosingMatcher<Optional<T>> {

/**
* Matcher that expects empty {@link Optional}.
*
* @param <T> type of optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> emptyOptional() {
return new OptionalEmpty<>();
}

@Override
protected boolean matchesSafely(Optional<T> value, Description mismatchDescription) {
mismatchDescription.appendText("is " + value);
return !value.isPresent();
}

@Override
public void describeTo(Description description) {
description.appendText("empty");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.hamcrest.optional;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.hamcrest.core.IsAnything;

import java.util.Optional;

import static org.hamcrest.core.IsEqual.equalTo;

/**
* Matcher for {@link Optional} that expects that value is present.
*
* @param <T> type of {@link Optional} value
*/
public class OptionalWithValue<T> extends TypeSafeDiagnosingMatcher<Optional<T>> {

private final Matcher<? super T> matcher;

/**
* Constructor.
*
* @param matcher matcher to validate present optional value
*/
public OptionalWithValue(Matcher<? super T> matcher) {
this.matcher = matcher;
}

/**
* Matcher for {@link Optional} that expects that value is present.
*
* @param <T> type of optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue() {
return new OptionalWithValue<>(IsAnything.anything("any"));
}

/**
* Matcher for {@link Optional} that expects that value is present and is equal to <code>value</code>
*
* @param <T> type of optional value
* @param value to validate present optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue(T value) {
return new OptionalWithValue<>(equalTo(value));
}

/**
* Matcher for {@link Optional} that expects that value is present and matches <code>matcher</code>
*
* @param <T> type of optional value
* @param matcher matcher to validate present optional value
* @return The matcher.
*/
public static <T> Matcher<Optional<T>> optionalWithValue(Matcher<? super T> matcher) {
return new OptionalWithValue<>(matcher);
}

@Override
protected boolean matchesSafely(Optional<T> value, Description mismatchDescription) {
mismatchDescription.appendText("is " + value);
return value.isPresent() && matcher.matches(value.get());
}

@Override
public void describeTo(Description description) {
description.appendText("present and matches ")
.appendDescriptionOf(matcher);
}
}
103 changes: 103 additions & 0 deletions hamcrest/src/test/java/org/hamcrest/optional/OptionalMatchersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package org.hamcrest.optional;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.optional.OptionalEmpty.emptyOptional;
import static org.hamcrest.optional.OptionalWithValue.optionalWithValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

import java.util.Optional;

import org.junit.Test;

public class OptionalMatchersTest {

@Test
public void checkEmptyOptional() {
assertThat(Optional.empty(), is(emptyOptional()));
assertThat(Optional.of(1), not(emptyOptional()));
}

@Test
public void checkEmptyOptionalFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.of(1), emptyOptional());
});
assertEquals("\n" +
"Expected: empty\n" +
" but: is Optional[1]", failure.getMessage());
}

@Test
public void checkEmptyOptionalIsFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.of(1), is(emptyOptional()));
});
assertEquals("\n" +
"Expected: is empty\n" +
" but: is Optional[1]", failure.getMessage());
}

@Test
public void checkEmptyOptionalIsNotFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.empty(), is(not(emptyOptional())));
});
assertEquals("\n" +
"Expected: is not empty\n" +
" but: was <Optional.empty>", failure.getMessage());
}

@Test
public void checkWithValue() {
assertThat(Optional.empty(), not(optionalWithValue()));
assertThat(Optional.of(1), is(optionalWithValue()));
}

@Test
public void checkWithMatchingValue() {
assertThat(Optional.empty(), not(optionalWithValue(equalTo(1))));
assertThat(Optional.of(1), is(optionalWithValue(equalTo(1))));
assertThat(Optional.of(1), not(optionalWithValue(equalTo(1L))));
}

@Test
public void checkWithLiteralValue() {
assertThat(Optional.empty(), not(optionalWithValue(1)));
assertThat(Optional.of(1), is(optionalWithValue(1)));
assertThat(Optional.of(1), not(optionalWithValue(1L)));
}

@Test
public void checkWithValueFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.empty(), is(optionalWithValue()));
});
assertEquals("\n" +
"Expected: is present and matches any\n" +
" but: is Optional.empty", failure.getMessage());
}

@Test
public void checkWithMatchingValueFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.empty(), is(optionalWithValue(equalTo(1))));
});
assertEquals("\n" +
"Expected: is present and matches <1>\n" +
" but: is Optional.empty", failure.getMessage());
}

@Test
public void checkWithLiteralValueFailure() {
AssertionError failure = assertThrows(AssertionError.class, () -> {
assertThat(Optional.of("text"), is(optionalWithValue("Hello, world")));
});
assertEquals("\n" +
"Expected: is present and matches \"Hello, world\"\n" +
" but: is Optional[text]", failure.getMessage());
}
}