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