comparison truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java @ 22135:e70b20f4bb00

Implementing API for Java/Truffle interop. Based around JavaInterop.asJavaObject and JavaInterop.asTruffleObject methods. Connected to TruffleVM via Symbol.as(Class) wrapper. Verified by extended TCK.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Mon, 07 Sep 2015 17:07:20 +0200
parents d045a505c2b3
children a583d7ffd285
comparison
equal deleted inserted replaced
22134:025869c88840 22135:e70b20f4bb00
22 * or visit www.oracle.com if you need additional information or have any 22 * or visit www.oracle.com if you need additional information or have any
23 * questions. 23 * questions.
24 */ 24 */
25 package com.oracle.truffle.tck; 25 package com.oracle.truffle.tck;
26 26
27 import com.oracle.truffle.api.interop.TruffleObject;
28 import com.oracle.truffle.api.interop.java.JavaInterop;
27 import com.oracle.truffle.api.source.Source; 29 import com.oracle.truffle.api.source.Source;
28 import com.oracle.truffle.api.vm.TruffleVM; 30 import com.oracle.truffle.api.vm.TruffleVM;
29 import java.io.IOException; 31 import java.io.IOException;
30 import java.util.Random; 32 import java.util.Random;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
31 import static org.junit.Assert.*; 35 import static org.junit.Assert.*;
32 import org.junit.Test; 36 import org.junit.Test;
33 37
34 /** 38 /**
35 * A collection of tests that can certify language implementation to be compliant with most recent 39 * A collection of tests that can certify language implementation to be compliant with most recent
36 * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and 40 * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and
37 * include in your test suite. 41 * include in your test suite.
38 */ 42 */
39 public abstract class TruffleTCK { 43 public abstract class TruffleTCK {
44 private static final Logger LOG = Logger.getLogger(TruffleTCK.class.getName());
45 private static final Random RANDOM = new Random();
40 private TruffleVM tckVM; 46 private TruffleVM tckVM;
41 47
42 protected TruffleTCK() { 48 protected TruffleTCK() {
43 } 49 }
44 50
54 * @throws java.lang.Exception thrown when the VM preparation fails 60 * @throws java.lang.Exception thrown when the VM preparation fails
55 */ 61 */
56 protected abstract TruffleVM prepareVM() throws Exception; 62 protected abstract TruffleVM prepareVM() throws Exception;
57 63
58 /** 64 /**
59 * Mimetype associated with your language. The mimetype will be passed to 65 * MIME type associated with your language. The MIME type will be passed to
60 * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source)} method of the 66 * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source)} method of the
61 * {@link #prepareVM() created TruffleVM}. 67 * {@link #prepareVM() created TruffleVM}.
62 * 68 *
63 * @return mime type of the tested language 69 * @return mime type of the tested language
64 */ 70 */
122 * 128 *
123 * @return code snippet invalid in the tested language 129 * @return code snippet invalid in the tested language
124 */ 130 */
125 protected abstract String invalidCode(); 131 protected abstract String invalidCode();
126 132
133 /**
134 * Name of a function that returns a compound object with members representing certain
135 * operations. In the JavaScript the object should look like:
136 *
137 * <pre>
138 * <b>var</b> obj = {
139 * 'fourtyTwo': function {@link #fourtyTwo()},
140 * 'plus': function {@link #plusInt()},
141 * 'returnsNull': function {@link #returnsNull()},
142 * 'returnsThis': function() { return obj; }
143 * };
144 * <b>return</b> obj;
145 * </pre>
146 *
147 * The returned object shall have three functions that will be obtained and used exactly as
148 * described in their Javadoc - e.g. {@link #fourtyTwo()}, {@link #plusInt()} and
149 * {@link #returnsNull()}. In addition to that there should be one more function
150 * <b>returnsThis</b> that will return the object itself again.
151 *
152 * @return name of a function that returns such compound object
153 */
154 protected String compoundObject() {
155 return null;
156 }
157
127 private TruffleVM vm() throws Exception { 158 private TruffleVM vm() throws Exception {
128 if (tckVM == null) { 159 if (tckVM == null) {
129 tckVM = prepareVM(); 160 tckVM = prepareVM();
130 } 161 }
131 return tckVM; 162 return tckVM;
147 178
148 assert 42 == n.intValue() : "The value is 42 = " + n.intValue(); 179 assert 42 == n.intValue() : "The value is 42 = " + n.intValue();
149 } 180 }
150 181
151 @Test 182 @Test
183 public void testFortyTwoWithCompoundObject() throws Exception {
184 CompoundObject obj = findCompoundSymbol("testFortyTwoWithCompoundObject");
185 if (obj == null) {
186 return;
187 }
188 Number res = obj.fourtyTwo();
189 assertEquals("Should be 42", 42, res.intValue());
190 }
191
192 @Test
152 public void testNull() throws Exception { 193 public void testNull() throws Exception {
153 if (getClass() == TruffleTCK.class) { 194 TruffleVM.Symbol retNull = findGlobalSymbol(returnsNull());
195
196 Object res = retNull.invoke(null).get();
197
198 assertNull("Should yield real Java null", res);
199 }
200
201 @Test
202 public void testNullInCompoundObject() throws Exception {
203 CompoundObject obj = findCompoundSymbol("testNullInCompoundObject");
204 if (obj == null) {
154 return; 205 return;
155 } 206 }
156 TruffleVM.Symbol retNull = findGlobalSymbol(returnsNull()); 207 Object res = obj.returnsNull();
157
158 Object res = retNull.invoke(null).get();
159
160 assertNull("Should yield real Java null", res); 208 assertNull("Should yield real Java null", res);
161 } 209 }
162 210
163 @Test 211 @Test
164 public void testPlusWithInts() throws Exception { 212 public void testPlusWithInts() throws Exception {
165 Random r = new Random(); 213 int a = RANDOM.nextInt(100);
166 int a = r.nextInt(100); 214 int b = RANDOM.nextInt(100);
167 int b = r.nextInt(100);
168 215
169 TruffleVM.Symbol plus = findGlobalSymbol(plusInt()); 216 TruffleVM.Symbol plus = findGlobalSymbol(plusInt());
170 217
171 Object res = plus.invoke(null, a, b).get(); 218 Number n = plus.invoke(null, a, b).as(Number.class);
172 219 assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") = " + n.intValue();
173 assert res instanceof Number : "+ on two ints should yield a number, but was: " + res; 220 }
174 221
175 Number n = (Number) res; 222 @Test
176 223 public void testPlusWithIntsOnCompoundObject() throws Exception {
224 int a = RANDOM.nextInt(100);
225 int b = RANDOM.nextInt(100);
226
227 CompoundObject obj = findCompoundSymbol("testPlusWithIntsOnCompoundObject");
228 if (obj == null) {
229 return;
230 }
231
232 Number n = obj.plus(a, b);
177 assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") = " + n.intValue(); 233 assert a + b == n.intValue() : "The value is correct: (" + a + " + " + b + ") = " + n.intValue();
178 } 234 }
179 235
180 @Test(expected = IOException.class) 236 @Test(expected = IOException.class)
181 public void testInvalidTestMethod() throws Exception { 237 public void testInvalidTestMethod() throws Exception {
187 243
188 @Test 244 @Test
189 public void testMaxOrMinValue() throws Exception { 245 public void testMaxOrMinValue() throws Exception {
190 TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers()); 246 TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers());
191 247
192 Object res = apply.invoke(null, new MaxMinObject(true)).get(); 248 TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(true));
249 Object res = apply.invoke(null, fn).get();
193 250
194 assert res instanceof Number : "result should be a number: " + res; 251 assert res instanceof Number : "result should be a number: " + res;
195 252
196 Number n = (Number) res; 253 Number n = (Number) res;
197 254
200 257
201 @Test 258 @Test
202 public void testMaxOrMinValue2() throws Exception { 259 public void testMaxOrMinValue2() throws Exception {
203 TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers()); 260 TruffleVM.Symbol apply = findGlobalSymbol(applyNumbers());
204 261
205 Object res = apply.invoke(null, new MaxMinObject(false)).get(); 262 TruffleObject fn = JavaInterop.asTruffleFunction(LongBinaryOperation.class, new MaxMinObject(false));
206 263 final TruffleVM.Symbol result = apply.invoke(null, fn);
207 assert res instanceof Number : "result should be a number: " + res; 264
208 265 try {
209 Number n = (Number) res; 266 String res = result.as(String.class);
210 267 fail("Cannot be converted to String: " + res);
268 } catch (ClassCastException ex) {
269 // correct
270 }
271
272 Number n = result.as(Number.class);
211 assert 28 == n.intValue() : "18 < 32 and plus 10"; 273 assert 28 == n.intValue() : "18 < 32 and plus 10";
212 } 274 }
213 275
214 @Test 276 @Test
215 public void testCoExistanceOfMultipleLanguageInstances() throws Exception { 277 public void testCoExistanceOfMultipleLanguageInstances() throws Exception {
222 284
223 assertNotSame("Two virtual machines allocated", vm1, vm2); 285 assertNotSame("Two virtual machines allocated", vm1, vm2);
224 286
225 int prev1 = 0; 287 int prev1 = 0;
226 int prev2 = 0; 288 int prev2 = 0;
227 Random r = new Random();
228 for (int i = 0; i < 10; i++) { 289 for (int i = 0; i < 10; i++) {
229 int quantum = r.nextInt(10); 290 int quantum = RANDOM.nextInt(10);
230 for (int j = 0; j < quantum; j++) { 291 for (int j = 0; j < quantum; j++) {
231 Object res = count1.invoke(null).get(); 292 Object res = count1.invoke(null).get();
232 assert res instanceof Number : "expecting number: " + res; 293 assert res instanceof Number : "expecting number: " + res;
233 assert ((Number) res).intValue() == ++prev1 : "expecting " + prev1 + " but was " + res; 294 ++prev1;
295 assert ((Number) res).intValue() == prev1 : "expecting " + prev1 + " but was " + res;
234 } 296 }
235 for (int j = 0; j < quantum; j++) { 297 for (int j = 0; j < quantum; j++) {
236 Object res = count2.invoke(null).get(); 298 Object res = count2.invoke(null).get();
237 assert res instanceof Number : "expecting number: " + res; 299 assert res instanceof Number : "expecting number: " + res;
238 assert ((Number) res).intValue() == ++prev2 : "expecting " + prev2 + " but was " + res; 300 ++prev2;
301 assert ((Number) res).intValue() == prev2 : "expecting " + prev2 + " but was " + res;
239 } 302 }
240 assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2; 303 assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2;
241 } 304 }
242 305
243 } 306 }
245 private TruffleVM.Symbol findGlobalSymbol(String name) throws Exception { 308 private TruffleVM.Symbol findGlobalSymbol(String name) throws Exception {
246 TruffleVM.Symbol s = vm().findGlobalSymbol(name); 309 TruffleVM.Symbol s = vm().findGlobalSymbol(name);
247 assert s != null : "Symbol " + name + " is not found!"; 310 assert s != null : "Symbol " + name + " is not found!";
248 return s; 311 return s;
249 } 312 }
313
314 private CompoundObject findCompoundSymbol(String name) throws Exception {
315 final String compoundObjectName = compoundObject();
316 if (compoundObjectName == null) {
317 final long introduced = 1441616302340L;
318 long wait = (System.currentTimeMillis() - introduced) / 3600;
319 if (wait < 100) {
320 wait = 100;
321 }
322 LOG.log(Level.SEVERE, "compoundObject() method not overriden! Skipping {1} test for now. But sleeping for {0} ms.", new Object[]{wait, name});
323 Thread.sleep(wait);
324 return null;
325 }
326 TruffleVM.Symbol s = vm().findGlobalSymbol(compoundObjectName);
327 assert s != null : "Symbol " + compoundObjectName + " is not found!";
328 CompoundObject obj = s.invoke(null).as(CompoundObject.class);
329 int traverse = RANDOM.nextInt(10);
330 while (traverse-- >= 0) {
331 obj = obj.returnsThis();
332 }
333 return obj;
334 }
335
336 interface CompoundObject {
337 Number fourtyTwo();
338
339 Number plus(int x, int y);
340
341 Object returnsNull();
342
343 CompoundObject returnsThis();
344 }
250 } 345 }