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