1 /*
  2  * Copyright (c) 2024, 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  * @modules jdk.incubator.code
 27  * @run testng TestTry
 28  */
 29 
 30 import org.testng.Assert;
 31 import org.testng.annotations.Test;
 32 
 33 import jdk.incubator.code.OpTransformer;
 34 import jdk.incubator.code.dialect.core.CoreOp;
 35 import jdk.incubator.code.Op;
 36 import jdk.incubator.code.interpreter.Interpreter;
 37 
 38 import java.lang.invoke.MethodHandles;
 39 import java.lang.reflect.Method;
 40 import jdk.incubator.code.CodeReflection;
 41 import java.util.ArrayList;
 42 import java.util.List;
 43 import java.util.Optional;
 44 import java.util.function.Consumer;
 45 import java.util.function.IntConsumer;
 46 import java.util.stream.Stream;
 47 
 48 public class TestTry {
 49 
 50     @CodeReflection
 51     public static void catching(IntConsumer c) {
 52         try {
 53             c.accept(0);
 54             c.accept(-1);
 55         } catch (IllegalStateException e) {
 56             consume(e);
 57             c.accept(1);
 58             c.accept(-1);
 59         } catch (IllegalArgumentException e) {
 60             consume(e);
 61             c.accept(2);
 62             c.accept(-1);
 63         }
 64         c.accept(3);
 65         c.accept(-1);
 66     }
 67 
 68     @Test
 69     public void testCatching() {
 70         CoreOp.FuncOp f = getFuncOp("catching");
 71 
 72         System.out.println(f.toText());
 73 
 74         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
 75 
 76         System.out.println(lf.toText());
 77 
 78         Consumer<IntConsumer> test = testConsumer(
 79                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
 80                 TestTry::catching);
 81 
 82         test.accept(i -> {
 83         });
 84         test.accept(i -> {
 85             if (i == 0) throw new IllegalStateException();
 86         });
 87         test.accept(i -> {
 88             if (i == 0) throw new IllegalArgumentException();
 89         });
 90         test.accept(i -> {
 91             if (i == 0) throw new NullPointerException();
 92         });
 93         test.accept(i -> {
 94             if (i == 0) throw new IllegalStateException();
 95             if (i == 1) throw new RuntimeException();
 96         });
 97         test.accept(i -> {
 98             if (i == 0) throw new IllegalArgumentException();
 99             if (i == 2) throw new RuntimeException();
100         });
101         test.accept(i -> {
102             if (i == 3) throw new IllegalStateException();
103         });
104     }
105 
106 
107     @CodeReflection
108     public static void catchThrowable(IntConsumer c) {
109         try {
110             c.accept(0);
111             c.accept(-1);
112         } catch (IllegalStateException e) {
113             consume(e);
114             c.accept(1);
115             c.accept(-1);
116         } catch (Throwable e) {
117             consume(e);
118             c.accept(2);
119             c.accept(-1);
120         }
121         c.accept(3);
122         c.accept(-1);
123     }
124 
125     @Test
126     public void testCatchThrowable() {
127         CoreOp.FuncOp f = getFuncOp("catchThrowable");
128 
129         System.out.println(f.toText());
130 
131         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
132 
133         System.out.println(lf.toText());
134 
135         Consumer<IntConsumer> test = testConsumer(
136                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
137                 TestTry::catchThrowable);
138 
139         test.accept(i -> {
140         });
141         test.accept(i -> {
142             if (i == 0) throw new IllegalStateException();
143         });
144         test.accept(i -> {
145             if (i == 0) throw new RuntimeException();
146         });
147         test.accept(i -> {
148             if (i == 0) throw new IllegalStateException();
149             if (i == 1) throw new RuntimeException();
150         });
151         test.accept(i -> {
152             if (i == 0) throw new RuntimeException();
153             if (i == 2) throw new RuntimeException();
154         });
155         test.accept(i -> {
156             if (i == 3) throw new IllegalStateException();
157         });
158     }
159 
160 
161     @CodeReflection
162     public static void catchNested(IntConsumer c) {
163         try {
164             c.accept(0);
165             c.accept(-1);
166             try {
167                 c.accept(1);
168                 c.accept(-1);
169             } catch (IllegalStateException e) {
170                 consume(e);
171                 c.accept(2);
172                 c.accept(-1);
173             }
174             c.accept(3);
175             c.accept(-1);
176         } catch (IllegalArgumentException e) {
177             consume(e);
178             c.accept(4);
179             c.accept(-1);
180         }
181         c.accept(5);
182         c.accept(-1);
183     }
184 
185     @Test
186     public void testCatchNested() {
187         CoreOp.FuncOp f = getFuncOp("catchNested");
188 
189         System.out.println(f.toText());
190 
191         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
192 
193         System.out.println(lf.toText());
194 
195         Consumer<IntConsumer> test = testConsumer(
196                 c -> Interpreter.invoke(MethodHandles.lookup(), lf, c),
197                 TestTry::catchNested);
198 
199         test.accept(i -> {
200         });
201         test.accept(i -> {
202             if (i == 0) throw new IllegalStateException();
203         });
204         test.accept(i -> {
205             if (i == 0) throw new IllegalArgumentException();
206         });
207         test.accept(i -> {
208             if (i == 1) throw new IllegalStateException();
209         });
210         test.accept(i -> {
211             if (i == 1) throw new IllegalArgumentException();
212         });
213         test.accept(i -> {
214             if (i == 1) throw new IllegalStateException();
215             if (i == 2) throw new IllegalArgumentException();
216         });
217         test.accept(i -> {
218             if (i == 1) throw new IllegalStateException();
219             if (i == 2) throw new RuntimeException();
220         });
221         test.accept(i -> {
222             if (i == 3) throw new IllegalArgumentException();
223         });
224         test.accept(i -> {
225             if (i == 3) throw new RuntimeException();
226         });
227         test.accept(i -> {
228             if (i == 3) throw new IllegalArgumentException();
229             if (i == 4) throw new RuntimeException();
230         });
231         test.accept(i -> {
232             if (i == 5) throw new RuntimeException();
233         });
234     }
235 
236 
237     static CoreOp.FuncOp getFuncOp(String name) {
238         Optional<Method> om = Stream.of(TestTry.class.getDeclaredMethods())
239                 .filter(m -> m.getName().equals(name))
240                 .findFirst();
241 
242         Method m = om.get();
243         return Op.ofMethod(m).get();
244     }
245 
246     static void consume(Throwable e) {
247     }
248 
249     static Consumer<IntConsumer> testConsumer(Consumer<IntConsumer> actualR, Consumer<IntConsumer> expectedR) {
250         return c -> {
251             List<Integer> actual = new ArrayList<>();
252             IntConsumer actualC = actual::add;
253             Throwable actualT = null;
254             try {
255                 actualR.accept(actualC.andThen(c));
256             } catch (Interpreter.InterpreterException e) {
257                 throw e;
258             } catch (Throwable t) {
259                 actualT = t;
260                 if (t instanceof AssertionError) {
261                     t.printStackTrace();
262                 }
263             }
264 
265             List<Integer> expected = new ArrayList<>();
266             IntConsumer expectedC = expected::add;
267             Throwable expectedT = null;
268             try {
269                 expectedR.accept(expectedC.andThen(c));
270             } catch (Throwable t) {
271                 expectedT = t;
272             }
273 
274             Assert.assertEquals(
275                     actualT != null ? actualT.getClass() : null,
276                     expectedT != null ? expectedT.getClass() : null);
277             Assert.assertEquals(actual, expected);
278         };
279     }
280 }