1/*
2 * Copyright (c) 2003, 2015, 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
24/**
25 * @test
26 * @bug 4870984
27 * @summary  JPDA: Add support for RFE 4856541 - varargs
28 * @author jjh
29 *
30 * @run build TestScaffold VMConnection TargetListener TargetAdapter
31 * @run compile -g VarargsTest.java
32 * @run driver VarargsTest
33 */
34import com.sun.jdi.*;
35import com.sun.jdi.event.*;
36import com.sun.jdi.request.*;
37
38import java.util.*;
39
40    /********** target program **********/
41
42class VarargsTarg {
43
44    // These are args that will get passed
45    static String[] strArray = new String[] {"a", "b"};
46    static int[] intArray = new int[] {1, 2};
47
48    // We will pass these to a varargs instance method
49    static VarargsTarg vt1 = new VarargsTarg("vt1", "");
50    static VarargsTarg vt2 = new VarargsTarg("vt2", "");
51
52    String iname;
53
54    VarargsTarg(String ... name) {
55        iname = "";
56        for (int ii = 0; ii < name.length; ii++) {
57            iname += name[ii];
58        }
59    }
60
61    public static void main(String[] args){
62        System.out.println("Howdy!");
63        /*
64         * This isn't really part of the test, it just shows
65         * the kinds of calls the debugger test will do and lets
66         * you verify how javac handles these calls.
67         */
68        System.out.println("debuggee: " + varString());
69        System.out.println("debuggee: " + varString(null));
70        System.out.println("debuggee: " + varString("a"));
71        System.out.println("debuggee: " + varString("b", "c"));
72        System.out.println("debuggee: " + fixedString(null));
73        System.out.println("debuggee: " + vt1.varStringInstance(vt1, vt2));
74        System.out.println("debuggge: " + varInt(1, 2, 3));
75        System.out.println("debuggee: " + varInteger( new Integer(89)));
76
77        // Should be autoboxed: javac converts the ints to Integers
78        // Needs a new method in java.lang.Integer which is only
79        // in the generics workspace.
80        System.out.println("debugggee: " + varInteger(3, 5, 6));
81
82        System.out.println("Goodbye from VarargsTarg!");
83        bkpt();
84    }
85    static void bkpt() {
86    }
87
88    /*
89     * Define the methods to be called from the debugger
90     */
91    static String fixedInt(int p1) {
92        return "" + p1;
93    }
94
95    static String fixedInteger(Integer p1) {
96        return "" + p1;
97    }
98
99     static String varInt(int... ss) {
100         String retVal = "";
101         for (int ii = 0; ii < ss.length; ii++) {
102             retVal += ss[ii];
103         }
104         return retVal;
105     }
106
107    static String varInteger(Integer... ss) {
108        String retVal = "";
109        for (int ii = 0; ii < ss.length; ii++) {
110            retVal += ss[ii];
111        }
112        return retVal;
113    }
114
115    static String varString(String... ss) {
116        if (ss == null) {
117            return "-null-";
118        }
119
120        String retVal = "";
121        for (int ii = 0; ii < ss.length; ii++) {
122            retVal += ss[ii];
123        }
124        return retVal;
125    }
126
127    static String varString2(int p1, String... ss) {
128        return p1 + varString(ss);
129    }
130
131    static String fixedString(String ss) {
132        return "-fixed-";
133    }
134
135    String varStringInstance(VarargsTarg... args) {
136        if (args == null) {
137            return "-null-";
138        }
139        //System.out.println("debugee: ss length = " + ss.length);
140        String retVal = iname + ": ";
141        for (int ii = 0; ii < args.length; ii++) {
142            retVal += args[ii].iname;
143        }
144        return retVal;
145    }
146
147}
148
149    /********** test program **********/
150
151public class VarargsTest extends TestScaffold {
152    ClassType targetClass;
153    ThreadReference mainThread;
154
155    VarargsTest (String args[]) {
156        super(args);
157    }
158
159    public static void main(String[] args)      throws Exception {
160        new VarargsTest(args).startTests();
161    }
162
163    void fail(String reason) {
164        failure(reason);
165    }
166
167    /*
168     * Call a method in the debuggee and verify the return value.
169     */
170    void doInvoke(Object ct, Method mm, List args, Object expected) {
171        StringReference returnValue = null;
172        try {
173            returnValue = doInvokeNoVerify(ct, mm, args);
174        } catch (Exception ee) {
175            fail("failure: invokeMethod got exception : " + ee);
176            ee.printStackTrace();
177            return;
178        }
179        if (!returnValue.value().equals(expected)) {
180            fail("failure: expected \"" + expected + "\", got \"" +
181                 returnValue.value() + "\"");
182        }
183    }
184
185    /*
186     * Call a method in the debuggee.
187     */
188    StringReference doInvokeNoVerify(Object ct, Method mm, List args)
189        throws Exception {
190        StringReference returnValue = null;
191        if (ct instanceof ClassType) {
192            returnValue = (StringReference)((ClassType)ct).
193                invokeMethod(mainThread, mm, args, 0);
194        } else {
195            returnValue = (StringReference)((ObjectReference)ct).
196                invokeMethod(mainThread, mm, args, 0);
197        }
198        return returnValue;
199    }
200
201    /********** test core **********/
202
203    protected void runTests() throws Exception {
204        /*
205         * Get to the top of main()
206         * to determine targetClass and mainThread
207         */
208        BreakpointEvent bpe = startToMain("VarargsTarg");
209        targetClass = (ClassType)bpe.location().declaringType();
210        mainThread = bpe.thread();
211
212        /*
213         * Run past the calls the debuggee makes
214         * just to see what they do.
215         */
216        bpe = resumeTo("VarargsTarg", "bkpt", "()V");
217
218        /*
219         * Find Method objects for varString and varString2
220         * Both are tested just to show that the code works
221         * if there is just one param or if there is more than one.
222         */
223        ReferenceType rt = findReferenceType("VarargsTarg");
224
225        List mList;
226
227        /*
228         * The test consists of calling the varargs static and instance methods
229         * (and constructor) passing primitives, Strings, and Objects, and also
230         * passing arrays of the above instead of individual args.
231         * The same code is used in the underlying JDI implementations
232         * for calling instance methods, static methods, and constructors
233         * so this test doesn't have to try all possible argument configurations
234         * with each type of method.
235         */
236
237        mList = rt.methodsByName("varString");
238        Method varString = (Method)mList.get(0);
239
240        mList = rt.methodsByName("varString2");
241        Method varString2 = (Method)mList.get(0);
242
243        if (!varString.isVarArgs()) {
244            fail("failure: varString is not flagged as being var args");
245        }
246        if (!varString2.isVarArgs()) {
247            fail("failure: varString2 is not flagged as being var args");
248        }
249
250        /*
251         * Setup arg lists for both varString and varString2 that
252         * have null in the varargs position.
253         */
254
255        {
256            // call varString()
257            ArrayList nullArg1 = new ArrayList(0);
258            doInvoke(targetClass, varString, nullArg1,  "");
259        }
260        {
261            // call varString(null)
262            ArrayList nullArg1 = new ArrayList(1);
263            nullArg1.add(null);
264            doInvoke(targetClass, varString, nullArg1,  "-null-");
265        }
266        {
267            // call varString(9)
268            ArrayList nullArg2 = new ArrayList(1);
269            nullArg2.add(vm().mirrorOf(9));
270            doInvoke(targetClass, varString2, nullArg2,  "9");
271        }
272        {
273            // call varString(9, null)
274            ArrayList nullArg2 = new ArrayList(2);
275            nullArg2.add(vm().mirrorOf(9));
276            nullArg2.add(null);
277            doInvoke(targetClass, varString2, nullArg2,  "9-null-");
278        }
279        {
280            ArrayList args1 = new ArrayList(4);
281            args1.add(vm().mirrorOf("1"));
282
283            // call varString("1")
284            doInvoke(targetClass, varString, args1, "1");
285
286            // call varString("1", "2")
287            args1.add(vm().mirrorOf("2"));
288            args1.add(vm().mirrorOf("3"));
289            args1.add(vm().mirrorOf("4"));
290            doInvoke(targetClass, varString, args1, "1234");
291        }
292        {
293            ArrayList args2 = new ArrayList(2);
294            args2.add(vm().mirrorOf(9));
295            args2.add(vm().mirrorOf("1"));
296
297            // call varString2(9, "1");
298            doInvoke(targetClass, varString2, args2, "91");
299
300            // call varString2(9, "1", "2");
301            args2.add(vm().mirrorOf("2"));
302            doInvoke(targetClass, varString2, args2, "912");
303        }
304
305        {
306            /*
307             * Passing an array of Strings should work too.
308             */
309            Field ff = targetClass.fieldByName("strArray");
310            Value vv1 = targetClass.getValue(ff);
311
312            // call varString(new String[] {"a", "b"})
313            ArrayList argsArray = new ArrayList(1);
314            argsArray.add(vv1);
315            doInvoke(targetClass, varString, argsArray, "ab");
316
317            /*
318             * But passing an array of Strings and another String
319             * should fail
320             */
321            argsArray.add(vm().mirrorOf("x"));
322            boolean isOk = false;
323            try {
324                // call varString(new String[] {"a", "b"}, "x")
325                doInvokeNoVerify(targetClass, varString, argsArray);
326            } catch (Exception ee) {
327                /*
328                 * Since the number of args passed is > than
329                 * the number of params, JDI assumes they are var args
330                 * and tries to put the array containing the "a" and
331                 * "be" elements into a the first element of an array
332                 * of Strings.  This fails because you can't store
333                 * an array into a String
334                 */
335                isOk = true;
336                //ee.printStackTrace();
337            }
338            if (!isOk) {
339                fail("failure: an array and a String didn't cause an exception");
340            }
341        }
342
343        {
344            /*
345             * Test calling instance method instead of static method,
346             * and passing non-String objects
347             */
348            Field vtField = targetClass.fieldByName("vt1");
349            Value vv1 = targetClass.getValue(vtField);
350
351            vtField = targetClass.fieldByName("vt2");
352            Value vv2 = targetClass.getValue(vtField);
353
354            /* Create a new instance by calling the varargs
355             * ctor.
356             * call new VarargsTarg("vt3", "xx");
357             */
358            Value vv3;
359            {
360                mList = rt.methodsByName("<init>");
361                Method ctor = (Method)mList.get(0);
362                if (!ctor.isVarArgs()) {
363                    fail("failure: Constructor is not varargs");
364                }
365                ArrayList argsArray = new ArrayList(2);
366                argsArray.add(vm().mirrorOf("vt3"));
367                argsArray.add(vm().mirrorOf("xx"));
368                vv3 = targetClass.newInstance(mainThread, ctor, argsArray, 0);
369            }
370            // call vt1.varStringInstance(vv1, vv2, vv3)
371            mList = rt.methodsByName("varStringInstance");
372            Method varStringInstance = (Method)mList.get(0);
373
374            ArrayList argsArray = new ArrayList(3);
375            argsArray.add(vv1);
376            argsArray.add(vv2);
377            argsArray.add(vv3);
378            doInvoke(vv1, varStringInstance, argsArray, "vt1: vt1vt2vt3xx");
379        }
380        {
381            /*
382             * tests with primitive types
383             */
384            List mlist;
385            Method mm;
386            ArrayList ll = new ArrayList(2);
387
388            // call fixedInt(21)
389            mlist = rt.methodsByName("fixedInt");
390            mm = (Method)mlist.get(0);
391            ll.add(vm().mirrorOf(21));
392            doInvoke(targetClass, mm, ll, "21");
393
394            // autoboxing is not implemented in JDI.
395            // call fixedInteger(21)
396            //mlist = rt.methodsByName("fixedInteger");
397            //mm = (Method)mlist.get(0);
398            //doInvoke(targetClass, mm, ll, "21");
399
400            mlist = rt.methodsByName("varInt");
401            mm = (Method)mlist.get(0);
402
403            // call varInt( new int[] {1, 2});
404            Field ff = targetClass.fieldByName("intArray");
405            Value vv1 = targetClass.getValue(ff);
406            ll.set(0, vv1);
407            doInvoke(targetClass, mm, ll, "12");
408
409            // call varInt(21, 22)
410            ll.set(0, vm().mirrorOf(21));
411            ll.add(vm().mirrorOf(22));
412            doInvoke(targetClass, mm, ll, "2122");
413
414            mlist = rt.methodsByName("varInteger");
415            mm = (Method)mlist.get(0);
416
417            // call varInteger(1, 2)
418            // autoboxing is not implemented.
419            //doInvoke(targetClass, mm, ll, "2122");
420        }
421
422        /*
423         * We don't really need this for the test, but
424         * but without it, we sometimes hit 4728096.
425         */
426        listenUntilVMDisconnect();
427        /*
428         * deal with results of test
429         * if anything has called failure("foo") testFailed will be true
430         */
431        if (!testFailed) {
432            println("VarargsTest: passed");
433        } else {
434            throw new Exception("VarargsTest: failed");
435        }
436    }
437}
438