either(...).or(...) broken for null values
Hello,
please take a look at the below test. I would expect all checks to succeed. However, the second and third do fail with:
java.lang.AssertionError:
Expected: ("" or null)
but: was null
The complete test code is this:
package zzz_small_tests;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.CombinableMatcher.either;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
public class HamcrestEitherOrTest {
@Rule
public ErrorCollector collector= new ErrorCollector();
@Test
public void testEitherOr() {
String _s1 = "";
collector.checkThat(_s1, either(equalTo("")).or(nullValue()));
String _s2 = null;
collector.checkThat(_s2, either(equalTo("")).or(nullValue()));
collector.checkThat(_s2, either(equalTo("")).or(nullValue(String.class)));
}
}
I guess this addresses the situation as issue #49.
True. So I guess, the most sensible workaround for now would be using anyOf(equalTo(""), nullValue())...
If a fix can not be implemented in the next release, then at least the API doc of CombinableEitherMatcher and the respective either() and or() methods should warn about this!?
This is caused by this little pice of code in TypeSafeDiagnosingMatcher
@Override
@SuppressWarnings("unchecked")
public final boolean matches(Object item) {
return item != null
&& expectedType.isInstance(item)
&& matchesSafely((T) item, new Description.NullDescription());
}
The item != null and expectedType.isInstance(item) is false for item = null
This can be fixed by adding this dirty hack to CombinableMatcher
@Override
public final boolean matches(Object item) {
if(this.matcher instanceof AnyOf)
{
AnyOf anyOf = (AnyOf) this.matcher;
List<Matcher<T>> matchers = (List<Matcher<T>>) anyOf.getMatchers();
Boolean matches = false;
for(Matcher eachMatcher : matchers)
{
if(eachMatcher.matches(item))
{
matches = true;
}
}
return matches;
}
else {
return super.matches(item);
}
}
Therefore TypeSafeDiagnosingMatcher's matches method must be non final and ShortcutCombination needs a getter for matchers.
I know this is really dirty, maybe someone can make a fix with this information. I'll also try to write a better fix for that.
EDIT:
I also wrote a test
private static final CombinableMatcher<String> EMPTY_STRING_OR_NULL = CombinableMatcher.either(equalTo("")).or(nullValue());
@Test public void
acceptNullOrEmptyString() {
assertMatches("or didn't pass", EMPTY_STRING_OR_NULL, null);
assertMatches("either didn't pass", EMPTY_STRING_OR_NULL, "");
}
Just ran into this issue. It's been 5 years after the initial report or even last comment so I wanted to bring attention to this again. Thank you for the workaround @marksarnold which I was able to use.
I also ran into this issue today. Has there been any progress on this, given that the issue was raised 5 years ago?