/* * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package nsk.share.jdi; import java.lang.reflect.*; import nsk.share.*; import nsk.share.jpda.ConversionUtils; import com.sun.jdi.*; /* * Class contains several common methods used by tests checking that values are * correctly converted as a result of JDI interface work (e.g. when method * 'ObjectReference.setValue(Field, Value)' is called) */ public class ValueConversionDebugger extends TestDebuggerType2 { protected static enum ValueType { BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE } /* * short aliases for ValueType members */ protected static ValueType BYTE = ValueType.BYTE; protected static ValueType CHAR = ValueType.CHAR; protected static ValueType SHORT = ValueType.SHORT; protected static ValueType INT = ValueType.INT; protected static ValueType LONG = ValueType.LONG; protected static ValueType FLOAT = ValueType.FLOAT; protected static ValueType DOUBLE = ValueType.DOUBLE; /* * Is information lost when given PrimitiveValue converted to the * primitive type representing by the destType */ public static boolean informationLoss(PrimitiveValue value, Class destType) { /* * Use reflection here to avoid large nested switches * (construct method name, method is located in the nsk.share.jpda.ConversionUtils) */ String methodNameToCall = "informationLoss"; Object param = null; if (value instanceof ByteValue) { methodNameToCall += "ByteTo"; param = new Byte(value.byteValue()); } else if (value instanceof ShortValue) { methodNameToCall += "ShortTo"; param = new Short(value.shortValue()); } else if (value instanceof CharValue) { methodNameToCall += "CharTo"; param = new Character(value.charValue()); } else if (value instanceof IntegerValue) { methodNameToCall += "IntTo"; param = new Integer(value.intValue()); } else if (value instanceof LongValue) { methodNameToCall += "LongTo"; param = new Long(value.longValue()); } else if (value instanceof FloatValue) { methodNameToCall += "FloatTo"; param = new Float(value.floatValue()); } else if (value instanceof DoubleValue) { methodNameToCall += "DoubleTo"; param = new Double(value.doubleValue()); } else throw new IllegalArgumentException("Illegal PrimitiveValue: " + value); if (!destType.isPrimitive()) throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type"); if (destType == Byte.TYPE) { methodNameToCall += "Byte"; } else if (destType == Short.TYPE) { methodNameToCall += "Short"; } else if (destType == Character.TYPE) { methodNameToCall += "Char"; } else if (destType == Integer.TYPE) { methodNameToCall += "Int"; } else if (destType == Long.TYPE) { methodNameToCall += "Long"; } else if (destType == Float.TYPE) { methodNameToCall += "Float"; } else if (destType == Double.TYPE) { methodNameToCall += "Double"; } else throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type"); java.lang.reflect.Method method; try { method = ConversionUtils.class.getMethod(methodNameToCall, param.getClass()); } catch (NoSuchMethodException e) { throw new Failure("Unexpected exception: " + e, e); } try { return (Boolean)method.invoke(null, new Object[]{param}); } catch (IllegalAccessException e) { throw new Failure("Unexpected exception: " + e, e); } catch (InvocationTargetException e) { throw new Failure("Unexpected exception: " + e, e); } } /* * Is given PrimitiveValue can be converted to the primitive type represented by the * destType without information loss */ public static boolean isValidConversion(PrimitiveValue value, Class destType) { return !informationLoss(value, destType); } /* * Method is used in subclasses for creation of tested values * (reflection is used to simplify coding) */ protected PrimitiveValue createValue(Object arr, int arrayIndex) { PrimitiveValue value; if (arr instanceof byte[]) { value = debuggee.VM().mirrorOf(Array.getByte(arr,arrayIndex)); } else if (arr instanceof char[]) { value = debuggee.VM().mirrorOf(Array.getChar(arr,arrayIndex)); } else if (arr instanceof double[]) { value = debuggee.VM().mirrorOf(Array.getDouble(arr,arrayIndex)); } else if (arr instanceof float[]) { value = debuggee.VM().mirrorOf(Array.getFloat(arr,arrayIndex)); } else if (arr instanceof int[]) { value = debuggee.VM().mirrorOf(Array.getInt(arr,arrayIndex)); } else if (arr instanceof long[]) { value = debuggee.VM().mirrorOf(Array.getLong(arr,arrayIndex)); } else if (arr instanceof short[]) { value = debuggee.VM().mirrorOf(Array.getShort(arr,arrayIndex)); } else { setSuccess(false); throw new TestBug("Unexpected object was passed in the 'createValue': " + arr); } return value; } /* * used by subclasses for debug output * (modified in the method 'isValidConversion') */ protected String lastConversion; /* * Is given PrimitiveValue can be converted to the primitive type represented by the given type * without information loss */ protected boolean isValidConversion(ValueType type, PrimitiveValue value) { com.sun.jdi.Type fromType = value.type(); boolean ret = false; lastConversion = " conversion from " + value + "(" + fromType + ")" + " to "; switch (type) { case BYTE: byte b = value.byteValue(); ret = isValidConversion(value, Byte.TYPE); lastConversion += b + "(byte)"; break; case CHAR: char c = value.charValue(); ret = isValidConversion(value, Character.TYPE); lastConversion += Integer.toHexString(c) + "(char)"; break; case DOUBLE: double d = value.doubleValue(); ret = isValidConversion(value, Double.TYPE); lastConversion += d + "(double)"; break; case FLOAT: float f = value.floatValue(); ret = isValidConversion(value, Float.TYPE); lastConversion += f + "(float)"; break; case INT: int i = value.intValue(); ret = isValidConversion(value, Integer.TYPE); lastConversion += i + "(int)"; break; case LONG: long j = value.longValue(); ret = isValidConversion(value, Long.TYPE); lastConversion += j + "(long)"; break; case SHORT: short s = value.shortValue(); ret = isValidConversion(value, Short.TYPE); lastConversion += s + "(short)"; break; default: throw new IllegalArgumentException("Invalid type: " + type); } return ret; } /* * Used in subclasses to check that given PrimitiveValue was correctly converted as a result * of JDI interface work (retValue - conversion result) * ( * example: * test assigns DoubleValue = 1.5 (value) to the byte Field (retValue - ByteValue = 1), * in this case we should check that value.byteValue() == retValue.byteValue() * ) */ protected void checkValueConversion(PrimitiveValue value, PrimitiveValue retValue) { boolean res; if (retValue instanceof ByteValue) { res = value.byteValue() != retValue.byteValue(); } else if (retValue instanceof ShortValue) { res = value.shortValue() != retValue.shortValue(); } else if (retValue instanceof CharValue) { res = value.charValue() != retValue.charValue(); } else if (retValue instanceof IntegerValue) { res = value.intValue() != retValue.intValue(); } else if (retValue instanceof LongValue) { res = value.longValue() != retValue.longValue(); } else if (retValue instanceof FloatValue) { res = value.floatValue() != retValue.floatValue(); } else if (retValue instanceof DoubleValue) { res = value.doubleValue() != retValue.doubleValue(); } else { throw new TestBug("Invalid value type in the 'checkValueConversion': " + retValue.type().name()); } if (res) { setSuccess(false); complain("Conversion error"); complain("From type: " + value.type().name() + ", to type: " + retValue.type().name()); complain(retValue + " != " + value); display(""); } } }