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