summaryrefslogtreecommitdiff
path: root/test/junit/scala/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'test/junit/scala/runtime')
-rw-r--r--test/junit/scala/runtime/LambdaDeserializerTest.java193
-rw-r--r--test/junit/scala/runtime/ScalaRunTimeTest.scala108
2 files changed, 247 insertions, 54 deletions
diff --git a/test/junit/scala/runtime/LambdaDeserializerTest.java b/test/junit/scala/runtime/LambdaDeserializerTest.java
new file mode 100644
index 0000000000..069eb4aab6
--- /dev/null
+++ b/test/junit/scala/runtime/LambdaDeserializerTest.java
@@ -0,0 +1,193 @@
+package scala.runtime;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public final class LambdaDeserializerTest {
+ private LambdaHost lambdaHost = new LambdaHost();
+
+ @Test
+ public void serializationPrivate() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByPrivateImplMethod();
+ Assert.assertEquals(f1.apply(true), reconstitute(f1).apply(true));
+ }
+
+ @Test
+ public void serializationStatic() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByStaticImplMethod();
+ Assert.assertEquals(f1.apply(true), reconstitute(f1).apply(true));
+ }
+
+ @Test
+ public void serializationVirtualMethodReference() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByVirtualMethodReference();
+ Assert.assertEquals(f1.apply(true), reconstitute(f1).apply(true));
+ }
+
+ @Test
+ public void serializationInterfaceMethodReference() {
+ F1<I, Object> f1 = lambdaHost.lambdaBackedByInterfaceMethodReference();
+ I i = new I() {
+ };
+ Assert.assertEquals(f1.apply(i), reconstitute(f1).apply(i));
+ }
+
+ @Test
+ public void serializationStaticMethodReference() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByStaticMethodReference();
+ Assert.assertEquals(f1.apply(true), reconstitute(f1).apply(true));
+ }
+
+ @Test
+ public void serializationNewInvokeSpecial() {
+ F0<Object> f1 = lambdaHost.lambdaBackedByConstructorCall();
+ Assert.assertEquals(f1.apply(), reconstitute(f1).apply());
+ }
+
+ @Test
+ public void uncached() {
+ F0<Object> f1 = lambdaHost.lambdaBackedByConstructorCall();
+ F0<Object> reconstituted1 = reconstitute(f1);
+ F0<Object> reconstituted2 = reconstitute(f1);
+ Assert.assertNotEquals(reconstituted1.getClass(), reconstituted2.getClass());
+ }
+
+ @Test
+ public void cached() {
+ HashMap<String, MethodHandle> cache = new HashMap<>();
+ F0<Object> f1 = lambdaHost.lambdaBackedByConstructorCall();
+ F0<Object> reconstituted1 = reconstitute(f1, cache);
+ F0<Object> reconstituted2 = reconstitute(f1, cache);
+ Assert.assertEquals(reconstituted1.getClass(), reconstituted2.getClass());
+ }
+
+ @Test
+ public void cachedStatic() {
+ HashMap<String, MethodHandle> cache = new HashMap<>();
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByStaticImplMethod();
+ // Check that deserialization of a static lambda always returns the
+ // same instance.
+ Assert.assertSame(reconstitute(f1, cache), reconstitute(f1, cache));
+
+ // (as is the case with regular invocation.)
+ Assert.assertSame(f1, lambdaHost.lambdaBackedByStaticImplMethod());
+ }
+
+ @Test
+ public void implMethodNameChanged() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByStaticImplMethod();
+ SerializedLambda sl = writeReplace(f1);
+ checkIllegalAccess(copySerializedLambda(sl, sl.getImplMethodName() + "___", sl.getImplMethodSignature()));
+ }
+
+ @Test
+ public void implMethodSignatureChanged() {
+ F1<Boolean, String> f1 = lambdaHost.lambdaBackedByStaticImplMethod();
+ SerializedLambda sl = writeReplace(f1);
+ checkIllegalAccess(copySerializedLambda(sl, sl.getImplMethodName(), sl.getImplMethodSignature().replace("Boolean", "Integer")));
+ }
+
+ private void checkIllegalAccess(SerializedLambda serialized) {
+ try {
+ LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), null, serialized);
+ throw new AssertionError();
+ } catch (IllegalArgumentException iae) {
+ if (!iae.getMessage().contains("Illegal lambda deserialization")) {
+ Assert.fail("Unexpected message: " + iae.getMessage());
+ }
+ }
+ }
+
+ private SerializedLambda copySerializedLambda(SerializedLambda sl, String implMethodName, String implMethodSignature) {
+ Object[] captures = new Object[sl.getCapturedArgCount()];
+ for (int i = 0; i < captures.length; i++) {
+ captures[i] = sl.getCapturedArg(i);
+ }
+ return new SerializedLambda(loadClass(sl.getCapturingClass()), sl.getFunctionalInterfaceClass(), sl.getFunctionalInterfaceMethodName(),
+ sl.getFunctionalInterfaceMethodSignature(), sl.getImplMethodKind(), sl.getImplClass(), implMethodName, implMethodSignature,
+ sl.getInstantiatedMethodType(), captures);
+ }
+
+ private Class<?> loadClass(String className) {
+ try {
+ return Class.forName(className.replace('/', '.'));
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ private <A, B> A reconstitute(A f1) {
+ return reconstitute(f1, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ private <A, B> A reconstitute(A f1, java.util.HashMap<String, MethodHandle> cache) {
+ try {
+ return (A) LambdaDeserializer.deserializeLambda(LambdaHost.lookup(), cache, writeReplace(f1));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private <A> SerializedLambda writeReplace(A f1) {
+ try {
+ Method writeReplace = f1.getClass().getDeclaredMethod("writeReplace");
+ writeReplace.setAccessible(true);
+ return (SerializedLambda) writeReplace.invoke(f1);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
+
+
+interface F1<A, B> extends Serializable {
+ B apply(A a);
+}
+
+interface F0<A> extends Serializable {
+ A apply();
+}
+
+class LambdaHost {
+ public F1<Boolean, String> lambdaBackedByPrivateImplMethod() {
+ int local = 42;
+ return (b) -> Arrays.asList(local, b ? "true" : "false", LambdaHost.this).toString();
+ }
+
+ @SuppressWarnings("Convert2MethodRef")
+ public F1<Boolean, String> lambdaBackedByStaticImplMethod() {
+ return (b) -> String.valueOf(b);
+ }
+
+ public F1<Boolean, String> lambdaBackedByStaticMethodReference() {
+ return String::valueOf;
+ }
+
+ public F1<Boolean, String> lambdaBackedByVirtualMethodReference() {
+ return Object::toString;
+ }
+
+ public F1<I, Object> lambdaBackedByInterfaceMethodReference() {
+ return I::i;
+ }
+
+ public F0<Object> lambdaBackedByConstructorCall() {
+ return String::new;
+ }
+
+ public static MethodHandles.Lookup lookup() {
+ return MethodHandles.lookup();
+ }
+}
+
+interface I {
+ default String i() { return "i"; };
+}
diff --git a/test/junit/scala/runtime/ScalaRunTimeTest.scala b/test/junit/scala/runtime/ScalaRunTimeTest.scala
index 9da197c71a..5bfb12610e 100644
--- a/test/junit/scala/runtime/ScalaRunTimeTest.scala
+++ b/test/junit/scala/runtime/ScalaRunTimeTest.scala
@@ -5,66 +5,66 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-/** Tests for the private class DefaultPromise */
+/** Tests for the runtime object ScalaRunTime */
@RunWith(classOf[JUnit4])
class ScalaRunTimeTest {
@Test
- def testIsTuple() {
- import ScalaRunTime.isTuple
- def check(v: Any) = {
- assertTrue(v.toString, isTuple(v))
+ def testStingOf() {
+ import ScalaRunTime.stringOf
+ import scala.collection._
+ import parallel.ParIterable
+
+ assertEquals("null", stringOf(null))
+ assertEquals( "\"\"", stringOf(""))
+
+ assertEquals("abc", stringOf("abc"))
+ assertEquals("\" abc\"", stringOf(" abc"))
+ assertEquals("\"abc \"", stringOf("abc "))
+
+ assertEquals("""Array()""", stringOf(Array.empty[AnyRef]))
+ assertEquals("""Array()""", stringOf(Array.empty[Int]))
+ assertEquals("""Array(1, 2, 3)""", stringOf(Array(1, 2, 3)))
+ assertEquals("""Array(a, "", " c", null)""", stringOf(Array("a", "", " c", null)))
+ assertEquals("""Array(Array("", 1, Array(5)), Array(1))""",
+ stringOf(Array(Array("", 1, Array(5)), Array(1))))
+
+ val map = Map(1->"", 2->"a", 3->" a", 4->null)
+ assertEquals(s"""${map.stringPrefix}(1 -> "", 2 -> a, 3 -> " a", 4 -> null)""", stringOf(map))
+ assertEquals(s"""${map.stringPrefix}(1 -> "", 2 -> a)""", stringOf(map, 2))
+
+ val iterable = Iterable("a", "", " c", null)
+ assertEquals(s"""${iterable.stringPrefix}(a, "", " c", null)""", stringOf(iterable))
+ assertEquals(s"""${iterable.stringPrefix}(a, "")""", stringOf(iterable, 2))
+
+ val parIterable = ParIterable("a", "", " c", null)
+ assertEquals(s"""${parIterable.stringPrefix}(a, "", " c", null)""", stringOf(parIterable))
+ assertEquals(s"""${parIterable.stringPrefix}(a, "")""", stringOf(parIterable, 2))
+
+ val traversable = new Traversable[Int] {
+ def foreach[U](f: Int => U): Unit = (0 to 3).foreach(f)
}
+ assertEquals(s"${traversable.stringPrefix}(0, 1, 2, 3)", stringOf(traversable))
+ assertEquals(s"${traversable.stringPrefix}(0, 1)", stringOf(traversable, 2))
- val s = ""
- check(Tuple1(s))
- check((s, s))
- check((s, s, s))
- check((s, s, s, s))
- check((s, s, s, s, s))
- check((s, s, s, s, s, s))
- check((s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
- check((s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s, s))
+ val tuple1 = Tuple1(0)
+ assertEquals("(0,)", stringOf(tuple1))
+ assertEquals("(0,)", stringOf(tuple1, 0))
+ assertEquals("(Array(0),)", stringOf(Tuple1(Array(0))))
- // some specialized variants will have mangled classnames
- check(Tuple1(0))
- check((0, 0))
- check((0, 0, 0))
- check((0, 0, 0, 0))
- check((0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
- check((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
+ val tuple2 = Tuple2(0, 1)
+ assertEquals("(0,1)", stringOf(tuple2))
+ assertEquals("(0,1)", stringOf(tuple2, 0))
+ assertEquals("(Array(0),1)", stringOf((Array(0), 1)))
- case class C()
- val c = new C()
- assertFalse(c.toString, isTuple(c))
+ val tuple3 = Tuple3(0, 1, 2)
+ assertEquals("(0,1,2)", stringOf(tuple3))
+ assertEquals("(0,1,2)", stringOf(tuple3, 0))
+ assertEquals("(Array(0),1,2)", stringOf((Array(0), 1, 2)))
+
+ val x = new Object {
+ override def toString(): String = "this is the stringOf string"
+ }
+ assertEquals(stringOf(x), "this is the stringOf string")
+ assertEquals(stringOf(x, 2), "this is the stringOf string")
}
}