package edu.washington.escience.myria.operator.apply;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.InvocationTargetException;
import org.joda.time.DateTime;
import org.junit.Test;
import edu.washington.escience.myria.DbException;
import edu.washington.escience.myria.Schema;
import edu.washington.escience.myria.Type;
import edu.washington.escience.myria.expression.CastExpression;
import edu.washington.escience.myria.expression.ConstantExpression;
import edu.washington.escience.myria.expression.Expression;
import edu.washington.escience.myria.expression.ExpressionOperator;
import edu.washington.escience.myria.expression.TypeExpression;
import edu.washington.escience.myria.expression.evaluate.ConstantEvaluator;
import edu.washington.escience.myria.expression.evaluate.ExpressionOperatorParameter;
public class CastTest {
/**
* Given a cast expression, evaluate it and return its value.
*
* @param op the expression
* @return the constant value
* @throws DbException if there is an error evaluating the expression
*/
private Object evaluateCastExpression(ExpressionOperator op, Type type) throws DbException {
Expression expr = new Expression("op", new CastExpression(op, new TypeExpression(type)));
ConstantEvaluator eval =
new ConstantEvaluator(expr, new ExpressionOperatorParameter(Schema.EMPTY_SCHEMA));
return eval.eval();
}
/**
* Given a cast expression, try and evaluate it. If successful, return it. If not, unwrap the expression to the root
* cause and return that.
*
* @param op the expression
* @return the constant value
* @throws Throwable the root cause of a failed Janino compilation.
*/
private Object evaluateCastAndUnrollException(ExpressionOperator op, Type type) throws Throwable {
try {
Object ans = evaluateCastExpression(op, type);
assertType(ans, type);
return ans;
} catch (DbException e) {
Throwable e1 = e.getCause();
if (e1 == null || !(e1 instanceof InvocationTargetException)) {
throw e;
}
Throwable e2 = e1.getCause();
if (e2 == null) {
throw e;
}
throw e2;
}
}
private void assertType(Object obj, Type type) throws DbException {
switch (type) {
case INT_TYPE:
assertEquals(obj.getClass(), Integer.class);
break;
case FLOAT_TYPE:
assertEquals(obj.getClass(), Float.class);
break;
case LONG_TYPE:
assertEquals(obj.getClass(), Long.class);
break;
case DOUBLE_TYPE:
assertEquals(obj.getClass(), Double.class);
break;
case STRING_TYPE:
assertEquals(obj.getClass(), String.class);
break;
case DATETIME_TYPE:
assertEquals(obj.getClass(), DateTime.class);
break;
case BOOLEAN_TYPE:
assertEquals(obj.getClass(), Boolean.class);
break;
}
}
@Test
public void testLongToInt() throws Throwable {
ConstantExpression val1 = new ConstantExpression(0L);
Object ans = evaluateCastAndUnrollException(val1, Type.INT_TYPE);
assertEquals(0, ans);
ConstantExpression val2 = new ConstantExpression((long) Integer.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.INT_TYPE);
assertEquals(Integer.MAX_VALUE, ans);
ConstantExpression val3 = new ConstantExpression((long) Integer.MIN_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.INT_TYPE);
assertEquals(Integer.MIN_VALUE, ans);
}
@Test
public void testFloatToInt() throws Throwable {
ConstantExpression val1 = new ConstantExpression(0.0f);
Object ans = evaluateCastAndUnrollException(val1, Type.INT_TYPE);
assertEquals(0, ans);
// cannot use Integer.MAX_VALUE here since converting (float) Integer.MAX_VALUE back to int will overflow.
float maxIntFloat = (float) 2.147483E9;
ConstantExpression val2 = new ConstantExpression(maxIntFloat);
ans = evaluateCastAndUnrollException(val2, Type.INT_TYPE);
assertEquals((int) maxIntFloat, ((Integer) ans).intValue());
float minIntFloat = Integer.MIN_VALUE;
ConstantExpression val3 = new ConstantExpression(minIntFloat);
ans = evaluateCastAndUnrollException(val3, Type.INT_TYPE);
assertEquals((int) minIntFloat, ans);
ConstantExpression val4 = new ConstantExpression((float) 3.25736);
ans = evaluateCastAndUnrollException(val4, Type.INT_TYPE);
assertEquals(3, ans);
}
@Test
public void testDoubleToInt() throws Throwable {
ConstantExpression val1 = new ConstantExpression(0.0);
Object ans = evaluateCastAndUnrollException(val1, Type.INT_TYPE);
assertEquals(0, ans);
double maxIntDouble = Integer.MAX_VALUE;
ConstantExpression val2 = new ConstantExpression(maxIntDouble);
ans = evaluateCastAndUnrollException(val2, Type.INT_TYPE);
assertEquals((int) maxIntDouble, ((Integer) ans).intValue());
double minIntDouble = Integer.MIN_VALUE;
ConstantExpression val3 = new ConstantExpression(minIntDouble);
ans = evaluateCastAndUnrollException(val3, Type.INT_TYPE);
assertEquals((int) minIntDouble, ans);
ConstantExpression val4 = new ConstantExpression((float) 3.25736);
ans = evaluateCastAndUnrollException(val4, Type.INT_TYPE);
assertEquals(3, ans);
}
@Test
public void testIntToFloat() throws Throwable {
float tolerance = (float) 1e-6;
ConstantExpression val1 = new ConstantExpression(0);
Object ans = evaluateCastAndUnrollException(val1, Type.FLOAT_TYPE);
assertEquals(Float.class, ans.getClass());
assertEquals(0.0f, ((Float) ans).floatValue(), tolerance);
ConstantExpression val2 = new ConstantExpression(Integer.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.FLOAT_TYPE);
assertEquals(Float.class, ans.getClass());
assertEquals(Integer.MAX_VALUE, ((Float) ans).floatValue(), tolerance);
ConstantExpression val3 = new ConstantExpression(Integer.MIN_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.FLOAT_TYPE);
assertEquals(Float.class, ans.getClass());
assertEquals(Integer.MIN_VALUE, ((Float) ans).floatValue(), tolerance);
}
@Test
public void testLongToFloat() throws Throwable {
float tolerance = (float) 1e-6;
ConstantExpression val1 = new ConstantExpression(0L);
Object ans = evaluateCastAndUnrollException(val1, Type.FLOAT_TYPE);
assertEquals(0.0f, ((Float) ans).floatValue(), tolerance);
ConstantExpression val2 = new ConstantExpression(Long.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.FLOAT_TYPE);
assertEquals(Long.MAX_VALUE, ((Float) ans).floatValue(), tolerance);
ConstantExpression val3 = new ConstantExpression(Long.MIN_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.FLOAT_TYPE);
assertEquals(Long.MIN_VALUE, ((Float) ans).floatValue(), tolerance);
}
@Test
public void testDoubleToFloat() throws Throwable {
float tolerance = (float) 1e-6;
ConstantExpression val1 = new ConstantExpression(0.0);
Object ans = evaluateCastAndUnrollException(val1, Type.FLOAT_TYPE);
assertEquals(0.0f, ((Float) ans).floatValue(), tolerance);
ConstantExpression val2 = new ConstantExpression((double) Float.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.FLOAT_TYPE);
assertEquals(Float.MAX_VALUE, ((Float) ans).floatValue(), tolerance);
ConstantExpression val3 = new ConstantExpression((double) -Float.MAX_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.FLOAT_TYPE);
assertEquals(-Float.MAX_VALUE, ((Float) ans).floatValue(), tolerance);
}
@Test
public void testIntToDouble() throws Throwable {
double tolerance = 1e-8;
ConstantExpression val1 = new ConstantExpression(0);
Object ans = evaluateCastAndUnrollException(val1, Type.DOUBLE_TYPE);
assertEquals(0.0f, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val2 = new ConstantExpression(Integer.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.DOUBLE_TYPE);
assertEquals(Integer.MAX_VALUE, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val3 = new ConstantExpression(Integer.MIN_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.DOUBLE_TYPE);
assertEquals(Integer.MIN_VALUE, ((Double) ans).doubleValue(), tolerance);
}
@Test
public void testFloatToDouble() throws Throwable {
double tolerance = 1e-8;
ConstantExpression val1 = new ConstantExpression(0.0f);
Object ans = evaluateCastAndUnrollException(val1, Type.DOUBLE_TYPE);
assertEquals(0.0f, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val2 = new ConstantExpression(Float.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.DOUBLE_TYPE);
assertEquals(Float.MAX_VALUE, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val3 = new ConstantExpression(-Float.MAX_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.DOUBLE_TYPE);
assertEquals(-Float.MAX_VALUE, ((Double) ans).doubleValue(), tolerance);
}
@Test
public void testLongToDouble() throws Throwable {
double tolerance = 1e-8;
ConstantExpression val1 = new ConstantExpression(0L);
Object ans = evaluateCastAndUnrollException(val1, Type.DOUBLE_TYPE);
assertEquals(0.0f, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val2 = new ConstantExpression(Long.MAX_VALUE);
ans = evaluateCastAndUnrollException(val2, Type.DOUBLE_TYPE);
assertEquals(Long.MAX_VALUE, ((Double) ans).doubleValue(), tolerance);
ConstantExpression val3 = new ConstantExpression(Long.MIN_VALUE);
ans = evaluateCastAndUnrollException(val3, Type.DOUBLE_TYPE);
assertEquals(Long.MIN_VALUE, ((Double) ans).doubleValue(), tolerance);
}
@Test
public void testToString() throws Throwable {
int test1 = Integer.MAX_VALUE;
ConstantExpression val1 = new ConstantExpression(test1);
Object ans = evaluateCastAndUnrollException(val1, Type.STRING_TYPE);
assertEquals(String.valueOf(test1), ans);
int test2 = Integer.MIN_VALUE;
ConstantExpression val2 = new ConstantExpression(test2);
ans = evaluateCastAndUnrollException(val2, Type.STRING_TYPE);
assertEquals(String.valueOf(test2), ans);
long test3 = Long.MAX_VALUE;
ConstantExpression val3 = new ConstantExpression(test3);
ans = evaluateCastAndUnrollException(val3, Type.STRING_TYPE);
assertEquals(String.valueOf(test3), ans);
long test4 = Long.MIN_VALUE;
ConstantExpression val4 = new ConstantExpression(test4);
ans = evaluateCastAndUnrollException(val4, Type.STRING_TYPE);
assertEquals(String.valueOf(test4), ans);
float test5 = (float) 12.6734;
ConstantExpression val5 = new ConstantExpression(test5);
ans = evaluateCastAndUnrollException(val5, Type.STRING_TYPE);
assertEquals(String.valueOf(test5), ans);
double test6 = 12.6734;
ConstantExpression val6 = new ConstantExpression(test6);
ans = evaluateCastAndUnrollException(val6, Type.STRING_TYPE);
assertEquals(String.valueOf(test6), ans);
}
@Test
public void testStringToNumeric() throws Throwable {
int test1 = Integer.MAX_VALUE;
ConstantExpression val1 = new ConstantExpression(String.valueOf(test1));
Object ans = evaluateCastAndUnrollException(val1, Type.INT_TYPE);
assertEquals(Integer.MAX_VALUE, ans);
int test2 = Integer.MIN_VALUE;
ConstantExpression val2 = new ConstantExpression(String.valueOf(test2));
ans = evaluateCastAndUnrollException(val2, Type.INT_TYPE);
assertEquals(test2, ans);
long test3 = Long.MAX_VALUE;
ConstantExpression val3 = new ConstantExpression(String.valueOf(test3));
ans = evaluateCastAndUnrollException(val3, Type.LONG_TYPE);
assertEquals(test3, ans);
long test4 = Long.MIN_VALUE;
ConstantExpression val4 = new ConstantExpression(String.valueOf(test4));
ans = evaluateCastAndUnrollException(val4, Type.LONG_TYPE);
assertEquals(test4, ans);
float test5 = (float) 12.6734;
ConstantExpression val5 = new ConstantExpression(String.valueOf(test5));
ans = evaluateCastAndUnrollException(val5, Type.FLOAT_TYPE);
assertEquals(test5, ans);
double test6 = 12.6734;
ConstantExpression val6 = new ConstantExpression(String.valueOf(test6));
ans = evaluateCastAndUnrollException(val6, Type.DOUBLE_TYPE);
assertEquals(test6, ans);
}
@Test(expected = IllegalArgumentException.class)
public void testLongToIntOverflow() throws Throwable {
ConstantExpression val = new ConstantExpression((long) Integer.MAX_VALUE + 1);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = IllegalArgumentException.class)
public void testLongToIntUnderflow() throws Throwable {
ConstantExpression val = new ConstantExpression((long) Integer.MIN_VALUE - 1);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testFloatToIntOverflow() throws Throwable {
ConstantExpression val = new ConstantExpression(Float.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
public void testFloatToIntUnderflow() throws Throwable {
ConstantExpression val = new ConstantExpression(-Float.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testDoubleToIntOverflow() throws Throwable {
ConstantExpression val = new ConstantExpression(Double.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testDoubleToIntUnderflow() throws Throwable {
ConstantExpression val = new ConstantExpression(-Double.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testFloatToLongOverflow() throws Throwable {
ConstantExpression val = new ConstantExpression(Float.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.LONG_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testFloatToLongUnderflow() throws Throwable {
ConstantExpression val = new ConstantExpression(-Float.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.LONG_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testDoubleToLongOverflow() throws Throwable {
ConstantExpression val = new ConstantExpression(Double.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.LONG_TYPE);
}
@Test(expected = ArithmeticException.class)
public void testDoubleToLongUnderflow() throws Throwable {
ConstantExpression val = new ConstantExpression(-Double.MAX_VALUE);
evaluateCastAndUnrollException(val, Type.LONG_TYPE);
}
@Test(expected = NumberFormatException.class)
public void testStringToIntFormatError() throws Throwable {
ConstantExpression val = new ConstantExpression("12.95");
evaluateCastAndUnrollException(val, Type.INT_TYPE);
}
@Test(expected = NumberFormatException.class)
public void testStringToFloatFormatError() throws Throwable {
ConstantExpression val = new ConstantExpression("12.95abc");
evaluateCastAndUnrollException(val, Type.FLOAT_TYPE);
}
@Test(expected = NumberFormatException.class)
public void testStringToDoubleFormatError() throws Throwable {
ConstantExpression val = new ConstantExpression("12.95abc");
evaluateCastAndUnrollException(val, Type.DOUBLE_TYPE);
}
@Test(expected = IllegalArgumentException.class)
public void unsupportedCast() throws IllegalArgumentException {
ExpressionOperator cast =
new CastExpression(new ConstantExpression(12), new TypeExpression(Type.DATETIME_TYPE));
cast.getOutputType(new ExpressionOperatorParameter());
}
@Test
public void supportedNoopCast() throws IllegalArgumentException {
ExpressionOperator cast =
new CastExpression(new ConstantExpression(12L), new TypeExpression(Type.LONG_TYPE));
assertEquals(Type.LONG_TYPE, cast.getOutputType(new ExpressionOperatorParameter()));
}
/* Self-cast tests. */
@Test
public void testSelfCastBoolean() throws Throwable {
ConstantExpression val1 = new ConstantExpression(true);
Object ans = evaluateCastAndUnrollException(val1, Type.BOOLEAN_TYPE);
assertEquals(true, ans);
}
@Test
public void testSelfCastDouble() throws Throwable {
ConstantExpression val1 = new ConstantExpression(2.0);
Object ans = evaluateCastAndUnrollException(val1, Type.DOUBLE_TYPE);
assertEquals(2.0, ans);
}
@Test
public void testSelfCastFloat() throws Throwable {
ConstantExpression val1 = new ConstantExpression(2.0f);
Object ans = evaluateCastAndUnrollException(val1, Type.FLOAT_TYPE);
assertEquals(2.0f, ans);
}
@Test
public void testSelfCastInt() throws Throwable {
ConstantExpression val1 = new ConstantExpression(Integer.MAX_VALUE);
Object ans = evaluateCastAndUnrollException(val1, Type.INT_TYPE);
assertEquals(Integer.MAX_VALUE, ans);
}
@Test
public void testSelfCastLong() throws Throwable {
ConstantExpression val1 = new ConstantExpression(Long.MAX_VALUE);
Object ans = evaluateCastAndUnrollException(val1, Type.LONG_TYPE);
assertEquals(Long.MAX_VALUE, ans);
}
@Test
public void testSelfCastString() throws Throwable {
ConstantExpression val1 = new ConstantExpression("abc123");
Object ans = evaluateCastAndUnrollException(val1, Type.STRING_TYPE);
assertEquals("abc123", ans);
}
}