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 import jdk.incubator.code.CodeReflection;
 25 import jdk.incubator.code.Op;
 26 import jdk.incubator.code.dialect.core.CoreOp;
 27 import jdk.incubator.code.interpreter.Interpreter;
 28 import org.junit.jupiter.api.Assertions;
 29 import org.junit.jupiter.params.ParameterizedTest;
 30 import org.junit.jupiter.params.provider.MethodSource;
 31 
 32 import java.lang.invoke.MethodHandles;
 33 import java.lang.reflect.InvocationTargetException;
 34 import java.lang.reflect.Method;
 35 import java.util.HashMap;
 36 import java.util.Map;
 37 import java.util.Set;
 38 import java.util.stream.Stream;
 39 
 40 /*
 41  * @test
 42  * @modules jdk.incubator.code
 43  * @run junit TestConcat
 44  */
 45 
 46 public class TestConcat {
 47 
 48     static final String TESTSTR = "TESTING STRING";
 49 
 50     @CodeReflection
 51     static String f() {
 52        int test = 1;
 53        String res = "HI " + TESTSTR + test;
 54        return res;
 55     }
 56 
 57 
 58     @CodeReflection
 59     public static String byteConcat1(byte b, String s) {
 60        return b + s;
 61     }
 62 
 63     @CodeReflection
 64     public static String byteConcat2(String s, byte b) {
 65         return s + b;
 66     }
 67 
 68     @CodeReflection
 69     public static String shortConcat1(short b, String s) {
 70         return b + s;
 71     }
 72 
 73     @CodeReflection
 74     public static String shortConcat2(String s, short b) {
 75         return s + b;
 76     }
 77 
 78     @CodeReflection
 79     public static String intConcat1(int b, String s) {
 80         return b + s;
 81     }
 82 
 83     @CodeReflection
 84     public static String intConcat2(String s, int b) {
 85         return s + b;
 86     }
 87 
 88     @CodeReflection
 89     public static String longConcat1(long b, String s) {
 90         return b + s;
 91     }
 92 
 93     @CodeReflection
 94     public static String longConcat2(String s, long b) {
 95         return s + b;
 96     }
 97 
 98     @CodeReflection
 99     public static String floatConcat1(float b, String s) {
100         return b + s;
101     }
102 
103     @CodeReflection
104     public static String floatConcat2(String s, float b) {
105         return s + b;
106     }
107 
108     @CodeReflection
109     public static String doubleConcat1(double b, String s) {
110         return b + s;
111     }
112 
113     @CodeReflection
114     public static String doubleConcat2(String s, double b) {
115         return s + b;
116     }
117 
118     @CodeReflection
119     public static String booleanConcat1(boolean b, String s) {
120         return b + s;
121     }
122 
123     @CodeReflection
124     public static String booleanConcat2(String s, boolean b) {
125         return s + b;
126     }
127 
128     @CodeReflection
129     public static String charConcat1(char b, String s) {
130         return b + s;
131     }
132     @CodeReflection
133     public static String charConcat2(String s, char b) {
134         return s + b;
135     }
136     @CodeReflection
137     public static String objectConcat1(Object b, String s) {
138         return b + s;
139     }
140 
141     @CodeReflection
142     public static String objectConcat2(String s, Object b) {
143         return s + b;
144     }
145 
146     @CodeReflection
147     public static String objectConcat3(TestObject b, String s) {
148         return b + s;
149     }
150 
151     @CodeReflection
152     public static String objectConcat4(String s, TestObject b) {
153         return s + b;
154     }
155 
156     @CodeReflection
157     public static String stringConcat(String b, String s) {
158         return b + s;
159     }
160 
161 
162     record TestMethodData(Class<?> first, Class<?> second, String third) {
163     }
164 
165     static final Map<Class<?>, Object> valMap;
166     static {
167         valMap = new HashMap<>();
168         valMap.put(byte.class, (byte) 42);
169         valMap.put(short.class, (short) 42);
170         valMap.put(int.class, 42);
171         valMap.put(long.class, (long) 42);
172         valMap.put(float.class, 42f);
173         valMap.put(double.class, 42d);
174         valMap.put(char.class, 'z');
175         valMap.put(boolean.class, false);
176         valMap.put(Object.class, new Object() {
177                     @Override
178                     public String toString() {
179                         return "I'm a test string.";
180                     }
181                 });
182         valMap.put(TestObject.class, new TestObject());
183         valMap.put(String.class, TESTSTR);
184     }
185     private static String testName(Class<?> n, Integer i){
186         return n.getSimpleName().toLowerCase() + "Concat" + i;
187     }
188 
189     public static Stream<TestMethodData> testData() {
190         Set<Class<?>> types = Set.of(byte.class, short.class, int.class, long.class, float.class,
191                 double.class, char.class, boolean.class, Object.class);
192 
193         //Types from types concatenated to strings left-to-right and right-to-left
194         Stream<TestMethodData> s1 = types.stream().map(t -> new TestMethodData(t, String.class, testName(t, 1)));
195         Stream<TestMethodData> s2 = types.stream().map(t -> new TestMethodData(String.class, t, testName(t, 2)));
196 
197         //Custom Object and basic string concat tests
198         Stream<TestMethodData> s3 = Stream.of(new TestMethodData(TestObject.class, String.class, testName(Object.class, 3)),
199                                       new TestMethodData(String.class, TestObject.class, testName(Object.class, 4)),
200                                       new TestMethodData(String.class, String.class, "stringConcat"));
201 
202         return Stream.concat(Stream.concat(s1,s2),s3);
203     }
204 
205     @ParameterizedTest
206     @MethodSource("testData")
207     public static void testRun(TestMethodData t) {
208         try {
209             Object[] args = new Object[] {valMap.get(t.first), valMap.get(t.second)};
210             Class<TestConcat> clazz = TestConcat.class;
211             Method method = clazz.getDeclaredMethod(t.third, t.first, t.second);
212             CoreOp.FuncOp f = Op.ofMethod(method).orElseThrow();
213             var res1 = Interpreter.invoke(MethodHandles.lookup(), f, args);
214             var res2 = method.invoke(null, args);
215 
216             Assertions.assertEquals(res2, res1);
217 
218         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
219             throw new RuntimeException(e);
220         }
221     }
222 
223     public static final class TestObject {
224         TestObject(){}
225 
226         @Override
227         public String toString() {
228             return "TestObject String";
229         }
230     }
231 }