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