/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.presto.bytecode.expression; import com.google.common.primitives.Primitives; import org.testng.annotations.Test; import static com.facebook.presto.bytecode.expression.BytecodeExpressionAssertions.assertBytecodeExpression; import static com.facebook.presto.bytecode.expression.BytecodeExpressions.getStatic; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; public class TestCastBytecodeExpression { public static final Object OBJECT_FIELD = "foo"; public static final boolean BOOLEAN_FIELD = true; public static final byte BYTE_FIELD = 99; public static final char CHAR_FIELD = 11; public static final short SHORT_FIELD = 22; public static final int INT_FIELD = 33; public static final long LONG_FIELD = 44; public static final float FLOAT_FIELD = 3.3f; public static final double DOUBLE_FIELD = 4.4; @Test public void testDownCastObject() throws Exception { assertBytecodeExpression(getStatic(getClass(), "OBJECT_FIELD").cast(String.class).invoke("length", int.class), ((String) OBJECT_FIELD).length(), "((String) " + getClass().getSimpleName() + ".OBJECT_FIELD).length()"); } @Test public void testCastBetweenObjectAndPrimitive() throws Exception { assertCast(getStatic(getClass(), "INT_FIELD"), 33, Object.class); assertCast(getStatic(getClass(), "INT_FIELD").cast(Object.class), 33, int.class); } @Test public void testInvalildCast() { // Cast between a boxed primitive and a primitive that are different assertInvalidCast(getStatic(getClass(), "INT_FIELD"), Double.class); assertInvalidCast(getStatic(getClass(), "INT_FIELD").cast(Integer.class), double.class); // Cast between two different boxed primitives assertInvalidCast(getStatic(getClass(), "INT_FIELD").cast(Integer.class), Double.class); // Cast between a primitive and an object (that is not java.lang.Object) assertInvalidCast(getStatic(getClass(), "OBJECT_FIELD").cast(String.class), double.class); assertInvalidCast(getStatic(getClass(), "INT_FIELD"), String.class); } @Test public void testCastPrimitive() throws Exception { assertPrimitiveCast("BOOLEAN_FIELD", boolean.class, BOOLEAN_FIELD); assertPrimitiveCast("BYTE_FIELD", byte.class, BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", char.class, (char) BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", short.class, (short) BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", int.class, (int) BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", long.class, (long) BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", float.class, (float) BYTE_FIELD); assertPrimitiveCast("BYTE_FIELD", double.class, (double) BYTE_FIELD); assertPrimitiveCast("CHAR_FIELD", byte.class, (byte) CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", char.class, CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", short.class, (short) CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", int.class, (int) CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", long.class, (long) CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", float.class, (float) CHAR_FIELD); assertPrimitiveCast("CHAR_FIELD", double.class, (double) CHAR_FIELD); assertPrimitiveCast("SHORT_FIELD", byte.class, (byte) SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", char.class, (char) SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", short.class, SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", int.class, (int) SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", long.class, (long) SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", float.class, (float) SHORT_FIELD); assertPrimitiveCast("SHORT_FIELD", double.class, (double) SHORT_FIELD); assertPrimitiveCast("INT_FIELD", byte.class, (byte) INT_FIELD); assertPrimitiveCast("INT_FIELD", char.class, (char) INT_FIELD); assertPrimitiveCast("INT_FIELD", short.class, (short) INT_FIELD); assertPrimitiveCast("INT_FIELD", int.class, INT_FIELD); assertPrimitiveCast("INT_FIELD", long.class, (long) INT_FIELD); assertPrimitiveCast("INT_FIELD", float.class, (float) INT_FIELD); assertPrimitiveCast("INT_FIELD", double.class, (double) INT_FIELD); assertPrimitiveCast("LONG_FIELD", byte.class, (byte) LONG_FIELD); assertPrimitiveCast("LONG_FIELD", char.class, (char) LONG_FIELD); assertPrimitiveCast("LONG_FIELD", short.class, (short) LONG_FIELD); assertPrimitiveCast("LONG_FIELD", int.class, (int) LONG_FIELD); assertPrimitiveCast("LONG_FIELD", long.class, LONG_FIELD); assertPrimitiveCast("LONG_FIELD", float.class, (float) LONG_FIELD); assertPrimitiveCast("LONG_FIELD", double.class, (double) LONG_FIELD); assertPrimitiveCast("FLOAT_FIELD", byte.class, (byte) FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", char.class, (char) FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", short.class, (short) FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", int.class, (int) FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", long.class, (long) FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", float.class, FLOAT_FIELD); assertPrimitiveCast("FLOAT_FIELD", double.class, (double) FLOAT_FIELD); assertPrimitiveCast("DOUBLE_FIELD", byte.class, (byte) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", char.class, (char) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", short.class, (short) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", int.class, (int) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", long.class, (long) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", float.class, (float) DOUBLE_FIELD); assertPrimitiveCast("DOUBLE_FIELD", double.class, DOUBLE_FIELD); } public void assertPrimitiveCast(String fieldName, Class<?> castToType, Object expected) throws Exception { // simple cast BytecodeExpression baseExpression = getStatic(getClass(), fieldName); assertCast(baseExpression, expected, castToType); // box result baseExpression = baseExpression.cast(castToType); Class<?> boxedType = Primitives.wrap(castToType); assertCast(baseExpression, expected, boxedType); // unbox the boxed result baseExpression = baseExpression.cast(boxedType); assertCast(baseExpression, expected, castToType); } public static void assertCast(BytecodeExpression expression, Object expectedValue, Class<?> castToType) throws Exception { BytecodeExpression castExpression = expression.cast(castToType); assertBytecodeExpression(castExpression, expectedValue, expectedCastRendering(expression.toString(), castToType)); assertEquals(castExpression.getType().getJavaClassName(), castToType.getName()); } public static void assertInvalidCast(BytecodeExpression expression, Class<?> castToType) { try { // Exception must be thrown here. // An exception that is thrown at actual byte code generation time is too late. At that point, stack trace is generally not useful. expression.cast(castToType); fail(); } catch (IllegalArgumentException ignored) { } } public static String expectedCastRendering(String expectedRendering, Class<?> castToType) { return "((" + castToType.getSimpleName() + ") " + expectedRendering + ")"; } }