1/*
2 * Copyright (c) 2012, 2013, 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 8003280
27 * @summary Add lambda tests
28 *   Test SAM conversion of method references in contexts of assignment, method/constructor argument,
29 *           return statement, array initializer, lambda expression body, conditional expression and cast.
30 * @compile SamConversion.java
31 * @run main SamConversion
32 */
33
34public class SamConversion {
35
36    static int assertionCount = 0;
37
38    static interface Foo {
39        Integer m(int i);
40    }
41
42    static interface Bar {
43        int m(Integer i) throws MyException;
44    }
45
46    private static void assertTrue(boolean b) {
47        assertionCount++;
48        if(!b)
49            throw new AssertionError();
50    }
51
52    private static int test1(Foo foo) {
53        return foo.m(1);
54    }
55
56    private static void test2(Bar bar, int result) {
57        try {
58            assertTrue(bar.m(1) == result);
59        } catch (Exception e){
60            assertTrue(false);
61        }
62    }
63
64    private static Bar test3(int i) {
65        switch (i) {
66        case 0:
67            return A::method1;
68        case 1:
69            return new A()::method2;
70        case 2:
71            return A::method3;
72        case 3:
73            return new A()::method4;
74        case 4:
75            return new A()::method5;
76        case 5:
77            return A::method6;
78        default:
79            return null;
80        }
81    }
82
83    /**
84     * Test SAM conversion of method reference in assignment context
85     */
86    private static void testAssignment() {
87        Foo foo = A::method1; //static reference, parameter type matching and return type matching
88        assertTrue(foo.m(1) == 2);
89
90        foo = new A()::method2; //instance reference, parameter type unboxing and return type boxing
91        assertTrue(foo.m(1) == 3);
92
93        foo = A::method3; //static reference, parameter type matching and return type boxing
94        assertTrue(foo.m(1) == 4);
95
96        foo = new A()::method4; //instance reference, parameter type unboxing and return type matching
97        assertTrue(foo.m(1) == 5);
98
99        foo = new A()::method5; //instance reference, parameter type unboxing and return type matching
100        assertTrue(foo.m(1) == 6);
101
102        Bar bar = A::method1;
103        try {
104            assertTrue(bar.m(1) == 2);
105        } catch (Exception e) {
106            assertTrue(false);
107        }
108
109        bar = new A()::method2;
110        try {
111            assertTrue(bar.m(1) == 3);
112        } catch (Exception e) {
113            assertTrue(false);
114        }
115
116        bar = A::method3;
117        try {
118            assertTrue(bar.m(1) == 4);
119        } catch (Exception e) {
120            assertTrue(false);
121        }
122
123        bar = new A()::method4;
124        try {
125            assertTrue(bar.m(1) == 5);
126        } catch (Exception e) {
127            assertTrue(false);
128        }
129
130        bar = new A()::method5;
131        try {
132            assertTrue(bar.m(1) == 6);
133        } catch (Exception e) {
134            assertTrue(false);
135        }
136    }
137
138    /**
139     * Test SAM conversion of method reference in method/constructor argument context
140     */
141    private static void testMethodArgument() {
142        assertTrue(test1(A::method1) == 2);
143        assertTrue(test1(new A()::method2) == 3);
144        assertTrue(test1(A::method3) == 4);
145        assertTrue(test1(new A()::method4) == 5);
146        assertTrue(test1(new A()::method5) == 6);
147        test2(A::method1, 2);
148        test2(new A()::method2, 3);
149        test2(A::method3, 4);
150        test2(new A()::method4, 5);
151        test2(new A()::method5, 6);
152    }
153
154    /**
155     * Test SAM conversion of method reference in return statement context
156     */
157    private static void testReturnStatement() {
158        Bar bar = test3(0);
159        try {
160            assertTrue(bar.m(1) == 2);
161        } catch (Exception e) {
162            assertTrue(false);
163        }
164        bar = test3(1);
165        try {
166            assertTrue(bar.m(1) == 3);
167        } catch (Exception e) {
168            assertTrue(false);
169        }
170        bar = test3(2);
171        try {
172            assertTrue(bar.m(1) == 4);
173        } catch (Exception e) {
174            assertTrue(false);
175        }
176        bar = test3(3);
177        try {
178            assertTrue(bar.m(1) == 5);
179        } catch (Exception e) {
180            assertTrue(false);
181        }
182        bar = test3(4);
183        try {
184            assertTrue(bar.m(1) == 6);
185        } catch (Exception e) {
186            assertTrue(false);
187        }
188        bar = test3(5);
189        try {
190            bar.m(1);
191            assertTrue(false);
192        } catch (MyException e) {
193        } catch (Exception e) {
194            assertTrue(false);
195        }
196    }
197
198    /**
199     * Test SAM conversion of method reference in cast context
200     */
201    private static void testCast() {
202        assertTrue(((Foo)A::method1).m(1) == 2);
203        try {
204            assertTrue(((Bar)new A()::method2).m(1) == 3);
205        } catch (Exception e) {
206            assertTrue(false);
207        }
208    }
209
210    /**
211     * Test SAM conversion of method reference in array initializer context
212     */
213    private static void testArrayInitializer() {
214        Object[] oarray = {"a", 1, (Foo)A::method3}; //last element need a cast
215        Object[] oarray2 = {"a", 1, (Bar)new A()::method4}; //last element need a cast
216        Foo[] farray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5};
217        Bar[] barray = {A::method1, new A()::method2, A::method3, new A()::method4, new A()::method5, A::method6};
218    }
219
220    /**
221     * Test SAM conversion of method reference in conditional expression context
222     */
223    private static void testConditionalExpression(boolean b) {
224        Foo f = b ? A::method3 : new A()::method5;
225        if(b)
226            assertTrue(f.m(1) == 4);
227        else
228            assertTrue(f.m(1) == 6);
229
230        Bar bar = b ? A::method1 : A::method6;
231        if(b) {
232            try {
233                assertTrue(bar.m(1) == 2);
234            } catch (Exception e) {
235                assertTrue(false);
236            }
237        }
238        else {
239            try {
240                bar.m(1);
241                assertTrue(false);
242            } catch (MyException e) {
243            } catch (Exception e) {
244                assertTrue(false);
245            }
246        }
247    }
248
249    /**
250     * Test SAM conversion of method reference in lambda expression body
251     */
252    private static void testLambdaExpressionBody() {
253        Foo f = n -> ((Foo)A::method3).m(n);
254        assertTrue(f.m(1) == 4);
255
256        Bar b = n -> { return ((Foo)new A()::method5).m(n); };
257        try {
258            assertTrue(b.m(1) == 6);
259        } catch (Exception e) {
260            assertTrue(false);
261        }
262    }
263
264    public static void main(String[] args) {
265        testAssignment();
266        testMethodArgument();
267        testReturnStatement();
268        testCast();
269        testArrayInitializer();
270        testConditionalExpression(true);
271        testConditionalExpression(false);
272        testLambdaExpressionBody();
273
274        assertTrue(assertionCount == 32);
275    }
276
277    static class MyException extends Exception {}
278
279    static class A {
280
281        int value = 0;
282
283        A() {
284        }
285
286        A(Foo f) {
287            value = f.m(9);
288        }
289
290        A(Bar b) {
291            try {
292                value = b.m(9);
293            } catch (MyException e){}
294        }
295
296        static Integer method1(int n) {
297            return n + 1;
298        }
299
300        int method2(Integer n) {
301            return value == 0 ? n + 2 : n + value;
302        }
303
304        static int method3(int n) {
305            return n + 3;
306        }
307
308        Integer method4(Integer n) {
309            return value == 0 ? n + 4 : n + value;
310        }
311
312        Integer method5(Integer n) {
313            return value == 0 ? new Integer(n + 5) : new Integer(n + value);
314        }
315
316        static int method6(Integer n) throws MyException{
317            throw new MyException();
318        }
319    }
320}
321