1 /*
   2  * Copyright (c) 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 8140450
  27  * @summary Basic test for the StackWalker::walk method
  28  * @run testng Basic
  29  */
  30 
  31 import java.lang.StackWalker.StackFrame;
  32 import java.util.List;
  33 import java.util.stream.Collectors;
  34 import static java.lang.StackWalker.Option.*;
  35 
  36 import org.testng.annotations.DataProvider;
  37 import org.testng.annotations.Test;
  38 import static org.testng.Assert.*;
  39 
  40 public class Basic {
  41     private static boolean verbose = false;
  42 
  43     @DataProvider(name = "stackDepths")
  44     public static Object[][] stackDepths() {
  45         return new Object[][] {
  46                 { new int[] { 12 },  new int[] { 4, 8, 12}      },
  47                 { new int[] { 18 },  new int[] { 8, 16, 20}     },
  48                 { new int[] { 32 },  new int[] { 16, 32, 64}    },
  49         };
  50     }
  51 
  52     /**
  53      * For a stack of a given depth, it creates a StackWalker with an estimate.
  54      * Test walking different number of frames
  55      */
  56     @Test(dataProvider = "stackDepths")
  57     public static void test(int[] depth, int[] estimates) {
  58         Basic test = new Basic(depth[0]);
  59         for (int estimate : estimates) {
  60             test.walk(estimate);
  61         }
  62     }
  63 
  64     private final int depth;
  65     Basic(int depth) {
  66         this.depth = depth;
  67     }
  68 
  69     /*
  70      * Setup a stack builder with the expected stack depth
  71      * Walk the stack and count the frames.
  72      */
  73     void walk(int estimate) {
  74         int limit = Math.min(depth, 16);
  75         List<StackFrame> frames = new StackBuilder(depth, limit).build();
  76         System.out.format("depth=%d estimate=%d expected=%d walked=%d%n",
  77                           depth, estimate, limit, frames.size());
  78         assertEquals(limit, frames.size());
  79     }
  80 
  81     class StackBuilder {
  82         private final int stackDepth;
  83         private final int limit;
  84         private int depth = 0;
  85         private List<StackFrame> result;
  86         StackBuilder(int stackDepth, int limit) {
  87             this.stackDepth = stackDepth; // build method;
  88             this.limit = limit;
  89         }
  90         List<StackFrame> build() {
  91             trace("build");
  92             m1();
  93             return result;
  94         }
  95         void m1() {
  96             trace("m1");
  97             m2();
  98         }
  99         void m2() {
 100             trace("m2");
 101             m3();
 102         }
 103         void m3() {
 104             trace("m3");
 105             m4();
 106         }
 107         void m4() {
 108             trace("m4");
 109             int remaining = stackDepth-depth-1;
 110             if (remaining >= 4) {
 111                 m1();
 112             } else {
 113                 filler(remaining);
 114             }
 115         }
 116         void filler(int i) {
 117             trace("filler");
 118             if (i == 0)
 119                 walk();
 120             else
 121                 filler(--i);
 122         }
 123 
 124         void walk() {
 125             StackWalker walker = StackWalker.create(RETAIN_CLASS_REFERENCE);
 126             result = walker.walk(s -> s.limit(limit).collect(Collectors.toList()));
 127         }
 128         void trace(String methodname) {
 129             ++depth;
 130             if (verbose)
 131                 System.out.format("%2d: %s%n", depth, methodname);
 132         }
 133     }
 134 
 135     static void assertEquals(int x, int y) {
 136         if (x != y) {
 137             throw new RuntimeException(x + " != " + y);
 138         }
 139     }
 140 }