/* Copyright (c) 2000-2006 hamcrest.org
*/
package de.mxro.thrd.hamcrest.core;
import de.mxro.thrd.hamcrest.Description;
import de.mxro.thrd.hamcrest.DiagnosingMatcher;
import de.mxro.thrd.hamcrest.Factory;
import de.mxro.thrd.hamcrest.Matcher;
/**
* Tests whether the value is an instance of a class.
* Classes of basic types will be converted to the relevant "Object" classes
*/
public class IsInstanceOf extends DiagnosingMatcher<Object> {
/**
*
*/
private static final long serialVersionUID = 1L;
public static boolean isSuperclass(Class<? extends Object> superclass, Class<? extends Object> clazz) {
if (superclass.equals(clazz)) return true;
// all classes are superlcass of Object
if (clazz.equals(Object.class)) return false;
return isSuperclass(superclass, clazz.getSuperclass());
}
/**
* necessary for GWT as Class.isInstance is not supported
* @param clazz
* @param object
* @return
*/
public static boolean instanceOf(Class<? extends Object> clazz, Object object) {
return isSuperclass(clazz, object.getClass());
}
private final Class<?> expectedClass;
private final Class<?> matchableClass;
/**
* Creates a new instance of IsInstanceOf
*
* @param expectedClass The predicate evaluates to true for instances of this class
* or one of its subclasses.
*/
public IsInstanceOf(Class<?> expectedClass) {
this.expectedClass = expectedClass;
this.matchableClass = matchableClass(expectedClass);
}
private static Class<?> matchableClass(Class<?> expectedClass) {
if (boolean.class.equals(expectedClass)) return Boolean.class;
if (byte.class.equals(expectedClass)) return Byte.class;
if (char.class.equals(expectedClass)) return Character.class;
if (double.class.equals(expectedClass)) return Double.class;
if (float.class.equals(expectedClass)) return Float.class;
if (int.class.equals(expectedClass)) return Integer.class;
if (long.class.equals(expectedClass)) return Long.class;
if (short.class.equals(expectedClass)) return Short.class;
return expectedClass;
}
@Override
protected boolean matches(Object item, Description mismatchDescription) {
if (null == item) {
mismatchDescription.appendText("null");
return false;
}
if (!instanceOf(matchableClass, item)) {
mismatchDescription.appendValue(item).appendText(" is a " + item.getClass().getName());
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("an instance of ")
.appendText(expectedClass.getName());
}
/**
* Is the value an instance of a particular type?
* This version assumes no relationship between the required type and
* the signature of the method that sets it up, for example in
* <code>assertThat(anObject, instanceOf(Thing.class));</code>
*/
@SuppressWarnings("unchecked")
@Factory
public static <T> Matcher<T> instanceOf(Class<?> type) {
return (Matcher<T>) new IsInstanceOf(type);
}
/**
* Is the value an instance of a particular type?
* Use this version to make generics conform, for example in
* the JMock clause <code>with(any(Thing.class))</code>
*/
@SuppressWarnings("unchecked")
@Factory
public static <T> Matcher<T> any(Class<T> type) {
return (Matcher<T>) new IsInstanceOf(type);
}
}