1 /*
   2  * Copyright (c) 2015, 2016, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /* @test
  27  * @bug 8139885
  28  * @bug 8143798
  29  * @run testng/othervm -ea -esa test.java.lang.invoke.SpreadCollectTest
  30  */
  31 
  32 package test.java.lang.invoke;
  33 
  34 import java.io.StringWriter;
  35 import java.lang.invoke.MethodHandle;
  36 import java.lang.invoke.MethodHandles;
  37 import java.lang.invoke.MethodHandles.Lookup;
  38 import java.lang.invoke.MethodType;
  39 import java.lang.invoke.WrongMethodTypeException;
  40 import java.util.*;
  41 
  42 import static java.lang.invoke.MethodType.methodType;
  43 
  44 import static org.testng.AssertJUnit.*;
  45 
  46 import org.testng.annotations.*;
  47 
  48 /**
  49  * Tests for the new asSpreader/asCollector API added in JEP 274.
  50  */
  51 public class SpreadCollectTest {
  52 
  53     static final Lookup LOOKUP = MethodHandles.lookup();
  54 
  55     @Test
  56     public static void testAsSpreader() throws Throwable {
  57         MethodHandle spreader = SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 3);
  58         assertEquals(SpreadCollect.MT_spreader, spreader.type());
  59         assertEquals("A456B", (String) spreader.invoke("A", new int[]{4, 5, 6}, "B"));
  60     }
  61 
  62     @Test
  63     public static void testAsSpreaderExample() throws Throwable {
  64         // test the JavaDoc asSpreader-with-pos example
  65         MethodHandle compare = LOOKUP.findStatic(Objects.class, "compare", methodType(int.class, Object.class, Object.class, Comparator.class));
  66         MethodHandle compare2FromArray = compare.asSpreader(0, Object[].class, 2);
  67         Object[] ints = new Object[]{3, 9, 7, 7};
  68         Comparator<Integer> cmp = (a, b) -> a - b;
  69         assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 0, 2), cmp) < 0);
  70         assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 1, 3), cmp) > 0);
  71         assertTrue((int) compare2FromArray.invoke(Arrays.copyOfRange(ints, 2, 4), cmp) == 0);
  72     }
  73 
  74     @DataProvider
  75     static Object[][] asSpreaderIllegalPositions() {
  76         return new Object[][]{{-7}, {3}, {19}};
  77     }
  78 
  79     @Test(dataProvider = "asSpreaderIllegalPositions")
  80     public static void testAsSpreaderIllegalPos(int p) throws Throwable {
  81         boolean caught = false;
  82         try {
  83             SpreadCollect.MH_forSpreading.asSpreader(p, Object[].class, 3);
  84         } catch (IllegalArgumentException iae) {
  85             assertEquals("bad spread position", iae.getMessage());
  86             caught = true;
  87         }
  88         assertTrue(caught);
  89     }
  90 
  91     @Test(expectedExceptions = {WrongMethodTypeException.class})
  92     public static void testAsSpreaderIllegalMethodType() {
  93         MethodHandle h = MethodHandles.dropArguments(MethodHandles.constant(String.class, ""), 0, int.class, int.class);
  94         MethodHandle s = h.asSpreader(String[].class, 1);
  95     }
  96 
  97     @Test(expectedExceptions = {NullPointerException.class})
  98     public static void testAsSpreaderNullArrayType() {
  99         SpreadCollect.MH_forSpreading.asSpreader(null, 0);
 100     }
 101 
 102     @Test(expectedExceptions = {NullPointerException.class})
 103     public static void testAsSpreaderNullArrayNonZeroLength() {
 104         SpreadCollect.MH_forSpreading.asSpreader(null, 1);
 105     }
 106 
 107     @Test(expectedExceptions = {IllegalArgumentException.class})
 108     public static void testAsSpreaderTooManyParams() throws Throwable {
 109         SpreadCollect.MH_forSpreading.asSpreader(1, int[].class, 6);
 110     }
 111 
 112     @Test
 113     public static void testAsCollector() throws Throwable {
 114         MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1);
 115         assertEquals(SpreadCollect.MT_collector1, collector.type());
 116         assertEquals("A4B", (String) collector.invoke("A", 4, "B"));
 117         collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 2);
 118         assertEquals(SpreadCollect.MT_collector2, collector.type());
 119         assertEquals("A45B", (String) collector.invoke("A", 4, 5, "B"));
 120         collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 3);
 121         assertEquals(SpreadCollect.MT_collector3, collector.type());
 122         assertEquals("A456B", (String) collector.invoke("A", 4, 5, 6, "B"));
 123     }
 124 
 125     @Test
 126     public static void testAsCollectorInvokeWithArguments() throws Throwable {
 127         MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 1);
 128         assertEquals(SpreadCollect.MT_collector1, collector.type());
 129         assertEquals("A4B", (String) collector.invokeWithArguments("A", 4, "B"));
 130         collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 2);
 131         assertEquals(SpreadCollect.MT_collector2, collector.type());
 132         assertEquals("A45B", (String) collector.invokeWithArguments("A", 4, 5, "B"));
 133         collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 3);
 134         assertEquals(SpreadCollect.MT_collector3, collector.type());
 135         assertEquals("A456B", (String) collector.invokeWithArguments("A", 4, 5, 6, "B"));
 136     }
 137 
 138     @Test
 139     public static void testAsCollectorLeading() throws Throwable {
 140         MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1);
 141         assertEquals(SpreadCollect.MT_collectorLeading1, collector.type());
 142         assertEquals("7Q", (String) collector.invoke(7, "Q"));
 143         collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 2);
 144         assertEquals(SpreadCollect.MT_collectorLeading2, collector.type());
 145         assertEquals("78Q", (String) collector.invoke(7, 8, "Q"));
 146         collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 3);
 147         assertEquals(SpreadCollect.MT_collectorLeading3, collector.type());
 148         assertEquals("789Q", (String) collector.invoke(7, 8, 9, "Q"));
 149     }
 150 
 151     @Test
 152     public static void testAsCollectorLeadingInvokeWithArguments() throws Throwable {
 153         MethodHandle collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 1);
 154         assertEquals(SpreadCollect.MT_collectorLeading1, collector.type());
 155         assertEquals("7Q", (String) collector.invokeWithArguments(7, "Q"));
 156         collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 2);
 157         assertEquals(SpreadCollect.MT_collectorLeading2, collector.type());
 158         assertEquals("78Q", (String) collector.invokeWithArguments(7, 8, "Q"));
 159         collector = SpreadCollect.MH_forCollectingLeading.asCollector(0, int[].class, 3);
 160         assertEquals(SpreadCollect.MT_collectorLeading3, collector.type());
 161         assertEquals("789Q", (String) collector.invokeWithArguments(7, 8, 9, "Q"));
 162     }
 163 
 164     @Test
 165     public static void testAsCollectorNone() throws Throwable {
 166         MethodHandle collector = SpreadCollect.MH_forCollecting.asCollector(1, int[].class, 0);
 167         assertEquals(SpreadCollect.MT_collector0, collector.type());
 168         assertEquals("AB", (String) collector.invoke("A", "B"));
 169     }
 170 
 171     @DataProvider
 172     static Object[][] asCollectorIllegalPositions() {
 173         return new Object[][]{{-1}, {17}};
 174     }
 175 
 176     @Test(dataProvider = "asCollectorIllegalPositions")
 177     public static void testAsCollectorIllegalPos(int p) {
 178         boolean caught = false;
 179         try {
 180             SpreadCollect.MH_forCollecting.asCollector(p, int[].class, 0);
 181         } catch (IllegalArgumentException iae) {
 182             assertEquals("bad collect position", iae.getMessage());
 183             caught = true;
 184         }
 185         assertTrue(caught);
 186     }
 187 
 188     @Test
 189     public static void testAsCollectorExample() throws Throwable {
 190         // test the JavaDoc asCollector-with-pos example
 191         StringWriter swr = new StringWriter();
 192         MethodHandle swWrite = LOOKUP.
 193                 findVirtual(StringWriter.class, "write", methodType(void.class, char[].class, int.class, int.class)).
 194                 bindTo(swr);
 195         MethodHandle swWrite4 = swWrite.asCollector(0, char[].class, 4);
 196         swWrite4.invoke('A', 'B', 'C', 'D', 1, 2);
 197         assertEquals("BC", swr.toString());
 198         swWrite4.invoke('P', 'Q', 'R', 'S', 0, 4);
 199         assertEquals("BCPQRS", swr.toString());
 200         swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
 201         assertEquals("BCPQRSZ", swr.toString());
 202     }
 203 
 204     static class SpreadCollect {
 205 
 206         static String forSpreading(String s1, int i1, int i2, int i3, String s2) {
 207             return s1 + i1 + i2 + i3 + s2;
 208         }
 209 
 210         static String forCollecting(String s1, int[] is, String s2) {
 211             StringBuilder sb = new StringBuilder(s1);
 212             for (int i : is) {
 213                 sb.append(i);
 214             }
 215             return sb.append(s2).toString();
 216         }
 217 
 218         static String forCollectingLeading(int[] is, String s) {
 219             return forCollecting("", is, s);
 220         }
 221 
 222         static final Class<SpreadCollect> SPREAD_COLLECT = SpreadCollect.class;
 223 
 224         static final MethodType MT_forSpreading = methodType(String.class, String.class, int.class, int.class, int.class, String.class);
 225         static final MethodType MT_forCollecting = methodType(String.class, String.class, int[].class, String.class);
 226         static final MethodType MT_forCollectingLeading = methodType(String.class, int[].class, String.class);
 227 
 228         static final MethodHandle MH_forSpreading;
 229         static final MethodHandle MH_forCollecting;
 230         static final MethodHandle MH_forCollectingLeading;
 231 
 232         static final MethodType MT_spreader = methodType(String.class, String.class, int[].class, String.class);
 233         static final MethodType MT_collector0 = methodType(String.class, String.class, String.class);
 234         static final MethodType MT_collector1 = methodType(String.class, String.class, int.class, String.class);
 235         static final MethodType MT_collector2 = methodType(String.class, String.class, int.class, int.class, String.class);
 236         static final MethodType MT_collector3 = methodType(String.class, String.class, int.class, int.class, int.class, String.class);
 237         static final MethodType MT_collectorLeading1 = methodType(String.class, int.class, String.class);
 238         static final MethodType MT_collectorLeading2 = methodType(String.class, int.class, int.class, String.class);
 239         static final MethodType MT_collectorLeading3 = methodType(String.class, int.class, int.class, int.class, String.class);
 240 
 241         static final String NONE_ERROR = "zero array length in MethodHandle.asCollector";
 242 
 243         static {
 244             try {
 245                 MH_forSpreading = LOOKUP.findStatic(SPREAD_COLLECT, "forSpreading", MT_forSpreading);
 246                 MH_forCollecting = LOOKUP.findStatic(SPREAD_COLLECT, "forCollecting", MT_forCollecting);
 247                 MH_forCollectingLeading = LOOKUP.findStatic(SPREAD_COLLECT, "forCollectingLeading", MT_forCollectingLeading);
 248             } catch (Exception e) {
 249                 throw new ExceptionInInitializerError(e);
 250             }
 251         }
 252 
 253     }
 254 
 255 }