package detective.core.runner;
import java.util.Map;
import groovy.lang.Closure;
import groovy.lang.GroovyInterceptable;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.MetaClass;
import groovy.lang.MetaClassRegistry;
import org.codehaus.groovy.reflection.MixinInMetaClass;
import org.codehaus.groovy.runtime.GroovyCategorySupport;
import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
import org.hamcrest.Matcher;
import org.junit.Assert;
import detective.core.dsl.DslException;
import detective.core.dsl.ParametersImpl;
import detective.core.dsl.WrappedObject;
import detective.core.matcher.IsEqual;
import detective.utils.Utils;
/**
* see groovy.time.TimeCategory
*
* http://groovy.codehaus.org/Operator+Overloading
*
* @author James Luo
*
*/
public class ExpectObjectWrapperWrapper extends GroovyObjectSupport implements WrappedObject<Object>, GroovyInterceptable{
private final Object realValue;
private final MetaClassRegistry registry;
public ExpectObjectWrapperWrapper(Object realValue){
this.realValue = realValue;
registry = MetaClassRegistryImpl.getInstance(MetaClassRegistryImpl.LOAD_DEFAULT);
}
@Override
public int hashCode() {
return realValue.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (obj instanceof ExpectObjectWrapperWrapper){
ExpectObjectWrapperWrapper other = (ExpectObjectWrapperWrapper) obj;
if (realValue == null) {
if (other.realValue != null)
return false;
} else if (!realValue.equals(other.realValue))
return false;
}else
if (obj instanceof PropertyToStringDelegate)
throw new WrongPropertyNameInDslException(((PropertyToStringDelegate)obj).getFullPropertyName());
else
return obj.equals(this.realValue);
return true;
}
@Override
public String toString() {
return "" + realValue;
}
public static void leftShift(Object self, Object obj){
throw new RuntimeException("Not supported!");
// if (self instanceof PropertyToStringDelegate){
// throw new WrongPropertyNameInDslException(((PropertyToStringDelegate)self).getFullPropertyName());
// }
//
// if (obj != null){
// if (obj instanceof Matcher){
// Assert.assertThat("", self, (Matcher)obj);
// }else{
//
// }
// } else{
// throw new DslException("We support org.hamcrest.Matcher only in expect section only for now. Maybe you didn't import static Matchers.*?, please note you can put a break point into your IDE for your DSL and inspect what the value is.");
// }
}
public void leftShift(Object obj){
if (obj != null){
if (obj instanceof Matcher){
assertThat(obj);
}else{
assertThat(IsEqual.equalTo(obj));
}
} else{
throw new DslException("We support org.hamcrest.Matcher only in expect section only for now. Maybe you didn't import static Matchers.*?, please note you can put a break point into your IDE for your DSL and inspect what the value is.");
}
}
private void assertThat(Object obj) {
try {
Assert.assertThat("", realValue, (Matcher)obj);
} catch (AssertionError e) {
try {
Assert.assertThat("", this, (Matcher)obj);
} catch (AssertionError e1) {
// we got AssertionError still? most likely because of first try, we throw out the original error
throw e;
}
}
}
public Object minus(Object obj){
if (obj instanceof ExpectObjectWrapperWrapper){
Object otherValue = ((ExpectObjectWrapperWrapper)obj).realValue;
if (realValue instanceof Integer || otherValue instanceof Integer)
return ((Number)realValue).intValue() - ((Number)otherValue).intValue();
else if (realValue instanceof Long || otherValue instanceof Long)
return ((Number)realValue).longValue() - ((Number)otherValue).longValue();
else if (realValue instanceof Number && otherValue instanceof Number)
return ((Number)realValue).doubleValue() - ((Number)otherValue).doubleValue();
}
throw new RuntimeException("minus support only number so far, please log a issue if you got this error, Thanks");
}
public Object plus(Object obj){
if (obj instanceof ExpectObjectWrapperWrapper){
Object otherValue = ((ExpectObjectWrapperWrapper)obj).realValue;
if (realValue instanceof Integer || otherValue instanceof Integer)
return ((Number)realValue).intValue() + ((Number)otherValue).intValue();
else if (realValue instanceof Long || otherValue instanceof Long)
return ((Number)realValue).longValue() + ((Number)otherValue).longValue();
else if (realValue instanceof Number && otherValue instanceof Number)
return ((Number)realValue).doubleValue() + ((Number)otherValue).doubleValue();
else if (realValue instanceof String && otherValue instanceof String)
return ((String)realValue) + ((String)otherValue);
}
throw new RuntimeException("plus support only number and String so far, please log a issue if you got this error, Thanks. Currnet values we got:" + realValue + ":" + obj );
}
public Object getRealValue() {
return realValue;
}
@Override
public Object getValue() {
return realValue;
}
@Override
public void setValue(Object value) {
throw new RuntimeException("We don't allow setup the value at this moment");
}
public Object getProperty(String property) {
//still have get property? it's maybe a map or list
if (realValue != null){
if (realValue instanceof GroovyObjectSupport){
Object value = ((GroovyObjectSupport)realValue).getProperty(property);
return new ExpectObjectWrapperWrapper(value);
}else{
MetaClass metaClass = registry.getMetaClass(realValue.getClass());
if (metaClass != null){
Object value = metaClass.getProperty(realValue, property);
return new ExpectObjectWrapperWrapper(value);
}
}
}
if (realValue == null)
throw new DslException("you try to access a property on a null object. property name: " + property);
return super.getProperty(property);
}
/**
* All method call will goes here first as we implements GroovyInterceptable
*/
public Object invokeMethod(String name, Object args) {
if (name.equals("leftShift"))
return this.getMetaClass().invokeMethod(this, name, args);
if (realValue != null){
if (realValue instanceof GroovyObject){
Object value = ((GroovyObject)realValue).invokeMethod(name, Utils.getRealValue(args));
return new ExpectObjectWrapperWrapper(value);
}else {
MetaClass metaClass = registry.getMetaClass(realValue.getClass());
if (metaClass != null){
Object value = metaClass.invokeMethod(realValue, name, Utils.getRealValue(args));
return new ExpectObjectWrapperWrapper(value);
}
}
}
return getMetaClass().invokeMethod(this, name, args);
}
}