1 /*
2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package nsk.share.jdi;
24 
25 import java.lang.reflect.*;
26 import nsk.share.*;
27 import nsk.share.jpda.ConversionUtils;
28 import com.sun.jdi.*;
29 
30 /*
31  * Class contains several common methods used by tests checking that values are
32  * correctly converted as a result of JDI interface work (e.g. when method
33  * 'ObjectReference.setValue(Field, Value)' is called)
34  */
35 public class ValueConversionDebugger extends TestDebuggerType2 {
36 
37     protected static enum ValueType {
38         BYTE,
39         CHAR,
40         SHORT,
41         INT,
42         LONG,
43         FLOAT,
44         DOUBLE
45     }
46 
47     /*
48      * short aliases for ValueType members
49      */
50     protected static ValueType BYTE = ValueType.BYTE;
51     protected static ValueType CHAR = ValueType.CHAR;
52     protected static ValueType SHORT = ValueType.SHORT;
53     protected static ValueType INT = ValueType.INT;
54     protected static ValueType LONG = ValueType.LONG;
55     protected static ValueType FLOAT = ValueType.FLOAT;
56     protected static ValueType DOUBLE = ValueType.DOUBLE;
57 
58     /*
59      * Is information lost when given PrimitiveValue converted to the
60      * primitive type representing by the destType
61      */
informationLoss(PrimitiveValue value, Class destType)62     public static boolean informationLoss(PrimitiveValue value, Class destType) {
63         /*
64          * Use reflection here to avoid large nested switches
65          * (construct method name, method is located in the nsk.share.jpda.ConversionUtils)
66          */
67         String methodNameToCall = "informationLoss";
68 
69         Object param = null;
70 
71         if (value instanceof ByteValue) {
72             methodNameToCall += "ByteTo";
73             param = new Byte(value.byteValue());
74         } else if (value instanceof ShortValue) {
75             methodNameToCall += "ShortTo";
76             param = new Short(value.shortValue());
77         } else if (value instanceof CharValue) {
78             methodNameToCall += "CharTo";
79             param = new Character(value.charValue());
80         } else if (value instanceof IntegerValue) {
81             methodNameToCall += "IntTo";
82             param = new Integer(value.intValue());
83         } else if (value instanceof LongValue) {
84             methodNameToCall += "LongTo";
85             param = new Long(value.longValue());
86         } else if (value instanceof FloatValue) {
87             methodNameToCall += "FloatTo";
88             param = new Float(value.floatValue());
89         } else if (value instanceof DoubleValue) {
90             methodNameToCall += "DoubleTo";
91             param = new Double(value.doubleValue());
92         } else
93             throw new IllegalArgumentException("Illegal PrimitiveValue: " + value);
94 
95         if (!destType.isPrimitive())
96             throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type");
97 
98         if (destType == Byte.TYPE) {
99             methodNameToCall += "Byte";
100         } else if (destType == Short.TYPE) {
101             methodNameToCall += "Short";
102         } else if (destType == Character.TYPE) {
103             methodNameToCall += "Char";
104         } else if (destType == Integer.TYPE) {
105             methodNameToCall += "Int";
106         } else if (destType == Long.TYPE) {
107             methodNameToCall += "Long";
108         } else if (destType == Float.TYPE) {
109             methodNameToCall += "Float";
110         } else if (destType == Double.TYPE) {
111             methodNameToCall += "Double";
112         } else
113             throw new IllegalArgumentException("Illegal destType: " + destType + ", should be primitive type");
114 
115         java.lang.reflect.Method method;
116         try {
117             method = ConversionUtils.class.getMethod(methodNameToCall, param.getClass());
118         } catch (NoSuchMethodException e) {
119             throw new Failure("Unexpected exception: " + e, e);
120         }
121 
122         try {
123             return (Boolean)method.invoke(null, new Object[]{param});
124         } catch (IllegalAccessException e) {
125             throw new Failure("Unexpected exception: " + e, e);
126         } catch (InvocationTargetException e) {
127             throw new Failure("Unexpected exception: " + e, e);
128         }
129     }
130 
131     /*
132      * Is given PrimitiveValue can be converted to the primitive type represented by the
133      * destType without information loss
134      */
isValidConversion(PrimitiveValue value, Class destType)135     public static boolean isValidConversion(PrimitiveValue value, Class destType) {
136         return !informationLoss(value, destType);
137     }
138 
139     /*
140      * Method is used in subclasses for creation of tested values
141      * (reflection is used to simplify coding)
142      */
createValue(Object arr, int arrayIndex)143     protected PrimitiveValue createValue(Object arr, int arrayIndex) {
144         PrimitiveValue value;
145 
146         if (arr instanceof byte[]) {
147             value = debuggee.VM().mirrorOf(Array.getByte(arr,arrayIndex));
148         } else if (arr instanceof char[]) {
149             value = debuggee.VM().mirrorOf(Array.getChar(arr,arrayIndex));
150         } else if (arr instanceof double[]) {
151             value = debuggee.VM().mirrorOf(Array.getDouble(arr,arrayIndex));
152         } else if (arr instanceof float[]) {
153             value = debuggee.VM().mirrorOf(Array.getFloat(arr,arrayIndex));
154         } else if (arr instanceof int[]) {
155             value = debuggee.VM().mirrorOf(Array.getInt(arr,arrayIndex));
156         } else if (arr instanceof long[]) {
157             value = debuggee.VM().mirrorOf(Array.getLong(arr,arrayIndex));
158         } else if (arr instanceof short[]) {
159             value = debuggee.VM().mirrorOf(Array.getShort(arr,arrayIndex));
160         } else {
161             setSuccess(false);
162             throw new TestBug("Unexpected object was passed in the 'createValue': " + arr);
163         }
164 
165         return value;
166     }
167 
168     /*
169      * used by subclasses for debug output
170      * (modified in the method 'isValidConversion')
171      */
172     protected String lastConversion;
173 
174     /*
175      * Is given PrimitiveValue can be converted to the primitive type represented by the given type
176      * without information loss
177      */
isValidConversion(ValueType type, PrimitiveValue value)178     protected boolean isValidConversion(ValueType type, PrimitiveValue value) {
179         com.sun.jdi.Type fromType = value.type();
180 
181         boolean ret = false;
182         lastConversion = " conversion from "
183                             + value + "(" + fromType + ")" + " to ";
184         switch (type) {
185         case BYTE:
186                 byte b = value.byteValue();
187                 ret = isValidConversion(value, Byte.TYPE);
188                 lastConversion += b + "(byte)";
189                 break;
190         case CHAR:
191                 char c = value.charValue();
192                 ret = isValidConversion(value, Character.TYPE);
193                 lastConversion += Integer.toHexString(c) + "(char)";
194                 break;
195         case DOUBLE:
196                 double d = value.doubleValue();
197                 ret = isValidConversion(value, Double.TYPE);
198                 lastConversion += d + "(double)";
199                 break;
200         case FLOAT:
201                 float f = value.floatValue();
202                 ret = isValidConversion(value, Float.TYPE);
203                 lastConversion += f + "(float)";
204                 break;
205         case INT:
206                 int i = value.intValue();
207                 ret = isValidConversion(value, Integer.TYPE);
208                 lastConversion += i + "(int)";
209                 break;
210         case LONG:
211                 long j = value.longValue();
212                 ret = isValidConversion(value, Long.TYPE);
213                 lastConversion += j + "(long)";
214                 break;
215         case SHORT:
216                 short s = value.shortValue();
217                 ret = isValidConversion(value, Short.TYPE);
218                 lastConversion += s + "(short)";
219                 break;
220         default:
221             throw new IllegalArgumentException("Invalid type: " + type);
222         }
223         return ret;
224     }
225 
226     /*
227      * Used in subclasses to check that given PrimitiveValue was correctly converted as a result
228      * of JDI interface work (retValue - conversion result)
229      * (
230      *  example:
231      *          test assigns DoubleValue = 1.5 (value) to the byte Field (retValue - ByteValue = 1),
232      *          in this case we should check that value.byteValue() == retValue.byteValue()
233      * )
234      */
checkValueConversion(PrimitiveValue value, PrimitiveValue retValue)235     protected void checkValueConversion(PrimitiveValue value, PrimitiveValue retValue) {
236         boolean res;
237 
238         if (retValue instanceof ByteValue) {
239             res = value.byteValue() != retValue.byteValue();
240         } else if (retValue instanceof ShortValue) {
241             res = value.shortValue() != retValue.shortValue();
242         } else if (retValue instanceof CharValue) {
243             res = value.charValue() != retValue.charValue();
244         } else if (retValue instanceof IntegerValue) {
245             res = value.intValue() != retValue.intValue();
246         } else if (retValue instanceof LongValue) {
247             res = value.longValue() != retValue.longValue();
248         } else if (retValue instanceof FloatValue) {
249             res = value.floatValue() != retValue.floatValue();
250         } else if (retValue instanceof DoubleValue) {
251             res = value.doubleValue() != retValue.doubleValue();
252         } else {
253             throw new TestBug("Invalid value type in the 'checkValueConversion': " + retValue.type().name());
254         }
255 
256         if (res) {
257             setSuccess(false);
258             complain("Conversion error");
259             complain("From type: " + value.type().name() + ", to type: " + retValue.type().name());
260             complain(retValue + " != " + value);
261             display("");
262         }
263     }
264 }
265