Mercurial > hg > truffle
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 } |