package com.oracle.truffle.api.test.polyglot;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.proxy.Proxy;
import org.graalvm.polyglot.proxy.ProxyArray;
import org.graalvm.polyglot.proxy.ProxyDate;
import org.graalvm.polyglot.proxy.ProxyDuration;
import org.graalvm.polyglot.proxy.ProxyExecutable;
import org.graalvm.polyglot.proxy.ProxyInstant;
import org.graalvm.polyglot.proxy.ProxyInstantiable;
import org.graalvm.polyglot.proxy.ProxyNativeObject;
import org.graalvm.polyglot.proxy.ProxyObject;
import org.graalvm.polyglot.proxy.ProxyTime;
import org.graalvm.polyglot.proxy.ProxyTimeZone;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
public class ProxySPITest extends AbstractPolyglotTest {
static final InteropLibrary INTEROP = InteropLibrary.getFactory().getUncached();
@ExportLibrary(InteropLibrary.class)
@SuppressWarnings("static-method")
static final class ProxyTestFunction implements TruffleObject {
TruffleObject lastFunction;
@ExportMessage
boolean isExecutable() {
return true;
}
@ExportMessage
Object execute(Object[] arguments) {
lastFunction = (TruffleObject) arguments[0];
return lastFunction;
}
}
@Before
public void before() {
setupEnv(Context.create());
}
private TruffleObject toInnerProxy(Proxy proxy) {
ProxyTestFunction f = new ProxyTestFunction();
context.asValue(f).execute(proxy);
return f.lastFunction;
}
@Test
public void testSimpleProxy() throws Throwable {
Proxy proxyOuter = new Proxy() {
};
Object proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
}
@Test
public void testArrayProxy() throws Throwable {
final long size = 42;
ProxyArray proxyOuter = new ProxyArray() {
int[] array = new int[(int) size];
{
Arrays.fill(array, 42);
}
public Object get(long index) {
return array[(int) index];
}
public void set(long index, Value value) {
array[(int) index] = value.asInt();
}
public long getSize() {
return size;
}
};
Object proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertTrue(INTEROP.hasArrayElements(proxyInner));
assertEquals(size, INTEROP.getArraySize(proxyInner));
for (int i = 0; i < size; i++) {
assertEquals(42, INTEROP.readArrayElement(proxyInner, i));
}
for (int i = 0; i < size; i++) {
INTEROP.writeArrayElement(proxyInner, i, 41);
}
for (int i = 0; i < size; i++) {
assertEquals(41, INTEROP.readArrayElement(proxyInner, i));
}
assertInvalidArrayIndex(() -> INTEROP.readArrayElement(proxyInner, 42));
assertInvalidArrayIndex(() -> INTEROP.readArrayElement(proxyInner, -1));
assertInvalidArrayIndex(() -> INTEROP.readArrayElement(proxyInner, Integer.MAX_VALUE));
assertInvalidArrayIndex(() -> INTEROP.readArrayElement(proxyInner, Integer.MIN_VALUE));
assertTrue(INTEROP.isArrayElementReadable(proxyInner, 41));
assertTrue(INTEROP.isArrayElementModifiable(proxyInner, 41));
assertTrue(INTEROP.isArrayElementRemovable(proxyInner, 41));
assertFalse(INTEROP.isArrayElementInsertable(proxyInner, 41));
assertFalse(INTEROP.isArrayElementReadable(proxyInner, 42));
assertFalse(INTEROP.isArrayElementModifiable(proxyInner, 42));
assertFalse(INTEROP.isArrayElementRemovable(proxyInner, 42));
assertTrue(INTEROP.isArrayElementInsertable(proxyInner, 42));
}
@Test
public void testArrayElementRemove() throws Throwable {
final int size = 42;
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(i);
}
ProxyArray proxyOuter = ProxyArray.fromList(list);
Object proxyInner = toInnerProxy(proxyOuter);
assertTrue(INTEROP.hasArrayElements(proxyInner));
assertEquals(size, INTEROP.getArraySize(proxyInner));
INTEROP.removeArrayElement(proxyInner, 10);
assertEquals(size - 1, INTEROP.getArraySize(proxyInner));
}
@Test
public void testProxyObject() throws Throwable {
Map<String, Object> values = new HashMap<>();
ProxyObject proxyOuter = ProxyObject.fromMap(values);
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertTrue(INTEROP.hasMembers(proxyInner));
assertEmpty(INTEROP.getMembers(proxyInner));
INTEROP.writeMember(proxyInner, "a", 42);
assertEquals(42, INTEROP.readMember(proxyInner, "a"));
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, "a"));
assertTrue(INTEROP.isMemberReadable(proxyInner, "a"));
assertTrue(INTEROP.isMemberModifiable(proxyInner, "a"));
assertTrue(INTEROP.isMemberRemovable(proxyInner, "a"));
assertFalse(INTEROP.isMemberInsertable(proxyInner, "a"));
assertFalse(INTEROP.isMemberInvocable(proxyInner, "a"));
assertFalse(INTEROP.isMemberInternal(proxyInner, "a"));
assertFalse(INTEROP.isMemberReadable(proxyInner, ""));
assertFalse(INTEROP.isMemberModifiable(proxyInner, ""));
assertFalse(INTEROP.isMemberRemovable(proxyInner, ""));
assertTrue(INTEROP.isMemberInsertable(proxyInner, ""));
assertFalse(INTEROP.isMemberInvocable(proxyInner, ""));
assertFalse(INTEROP.isMemberInternal(proxyInner, ""));
INTEROP.removeMember(proxyInner, "a");
assertEmpty(INTEROP.getMembers(proxyInner));
}
@Test
public void testProxyObjectUnsupported() throws Throwable {
ProxyObject proxyOuter = new ProxyObject() {
public void putMember(String key, Value value) {
throw new UnsupportedOperationException();
}
public boolean hasMember(String key) {
return true;
}
public ProxyArray getMemberKeys() {
return null;
}
public Object getMember(String key) {
throw new UnsupportedOperationException();
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertEmpty(INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertTrue(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
}
@Test
public void testProxyNativeObject() throws Throwable {
ProxyNativeObject proxyOuter = new ProxyNativeObject() {
public long asPointer() {
return 42;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertTrue(INTEROP.isPointer(proxyInner));
assertEquals(42L, INTEROP.asPointer(proxyInner));
}
@Test
public void testProxyExecutable() throws Throwable {
ProxyExecutable proxyOuter = new ProxyExecutable() {
public Object execute(Value... t) {
return t[0].asInt();
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertTrue(INTEROP.isExecutable(proxyInner));
assertEquals(42, INTEROP.execute(proxyInner, 42));
}
@Test
public void testProxyInstantiable() throws Throwable {
ProxyInstantiable proxyOuter = new ProxyInstantiable() {
@Override
public Object newInstance(Value... t) {
return t[0].asInt();
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertTrue(INTEROP.isInstantiable(proxyInner));
assertEquals(42, INTEROP.instantiate(proxyInner, 42));
}
@Test
public void testProxyDate() throws Throwable {
LocalDate date = LocalDate.now();
ProxyDate proxyOuter = new ProxyDate() {
public LocalDate asDate() {
return date;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asTime(proxyInner));
assertUnsupported(() -> INTEROP.asTimeZone(proxyInner));
assertUnsupported(() -> INTEROP.asDuration(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertFalse(INTEROP.isTime(proxyInner));
assertFalse(INTEROP.isTimeZone(proxyInner));
assertFalse(INTEROP.isDuration(proxyInner));
assertTrue(INTEROP.isDate(proxyInner));
assertEquals(date, INTEROP.asDate(proxyInner));
}
@Test
public void testProxyTime() throws Throwable {
LocalTime time = LocalTime.now();
ProxyTime proxyOuter = new ProxyTime() {
public LocalTime asTime() {
return time;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asDate(proxyInner));
assertUnsupported(() -> INTEROP.asTimeZone(proxyInner));
assertUnsupported(() -> INTEROP.asDuration(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertFalse(INTEROP.isDate(proxyInner));
assertFalse(INTEROP.isTimeZone(proxyInner));
assertFalse(INTEROP.isDuration(proxyInner));
assertTrue(INTEROP.isTime(proxyInner));
assertEquals(time, INTEROP.asTime(proxyInner));
}
@Test
public void testProxyTimeZone() throws Throwable {
ZoneId zone = ZoneId.of("UTC+1");
ProxyTimeZone proxyOuter = new ProxyTimeZone() {
public ZoneId asTimeZone() {
return zone;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asDate(proxyInner));
assertUnsupported(() -> INTEROP.asTime(proxyInner));
assertUnsupported(() -> INTEROP.asDuration(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertFalse(INTEROP.isDate(proxyInner));
assertFalse(INTEROP.isTime(proxyInner));
assertFalse(INTEROP.isDuration(proxyInner));
assertTrue(INTEROP.isTimeZone(proxyInner));
assertEquals(zone, INTEROP.asTimeZone(proxyInner));
}
@Test
public void testProxyInstant() throws Throwable {
Instant instant = Instant.now();
ProxyInstant proxyOuter = new ProxyInstant() {
public Instant asInstant() {
return instant;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asDuration(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertFalse(INTEROP.isDuration(proxyInner));
assertTrue(INTEROP.isTimeZone(proxyInner));
assertTrue(INTEROP.isTime(proxyInner));
assertTrue(INTEROP.isDate(proxyInner));
assertTrue(INTEROP.isInstant(proxyInner));
assertEquals(instant.atZone(ZoneId.of("UTC")).toLocalDate(), INTEROP.asDate(proxyInner));
assertEquals(instant.atZone(ZoneId.of("UTC")).toLocalTime(), INTEROP.asTime(proxyInner));
assertEquals(ZoneId.of("UTC"), INTEROP.asTimeZone(proxyInner));
assertEquals(instant, INTEROP.asInstant(proxyInner));
}
@Test
public void testProxyDuration() throws Throwable {
Duration duration = Duration.ofMillis(100);
ProxyDuration proxyOuter = new ProxyDuration() {
public Duration asDuration() {
return duration;
}
};
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.instantiate(proxyInner));
assertUnsupported(() -> INTEROP.asPointer(proxyInner));
assertUnsupported(() -> INTEROP.getArraySize(proxyInner));
assertUnsupported(() -> INTEROP.getMembers(proxyInner));
assertUnsupported(() -> INTEROP.readMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.writeMember(proxyInner, "", ""));
assertUnsupported(() -> INTEROP.removeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.readArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertUnsupported(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertUnsupported(() -> INTEROP.invokeMember(proxyInner, ""));
assertUnsupported(() -> INTEROP.execute(proxyInner));
assertUnsupported(() -> INTEROP.asDate(proxyInner));
assertUnsupported(() -> INTEROP.asTime(proxyInner));
assertUnsupported(() -> INTEROP.asTimeZone(proxyInner));
assertFalse(INTEROP.isNumber(proxyInner));
assertFalse(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isExecutable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertFalse(INTEROP.hasMembers(proxyInner));
assertFalse(INTEROP.hasArrayElements(proxyInner));
assertFalse(INTEROP.isPointer(proxyInner));
assertFalse(INTEROP.isDate(proxyInner));
assertFalse(INTEROP.isTime(proxyInner));
assertFalse(INTEROP.isTimeZone(proxyInner));
assertTrue(INTEROP.isDuration(proxyInner));
assertEquals(duration, INTEROP.asDuration(proxyInner));
}
static class Invalid0 implements ProxyDuration, ProxyDate {
public LocalDate asDate() {
return LocalDate.now();
}
public Duration asDuration() {
return Duration.ofMillis(100);
}
}
@Test
public void testInvalidCombination0() throws Throwable {
Invalid0 proxyOuter = new Invalid0();
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertInvalidState(() -> INTEROP.isDate(proxyInner));
assertInvalidState(() -> INTEROP.isDuration(proxyInner));
assertInvalidState(() -> INTEROP.asDuration(proxyInner));
assertInvalidState(() -> INTEROP.asDate(proxyInner));
}
static class Invalid1 implements ProxyDate, ProxyTimeZone {
public ZoneId asTimeZone() {
return ZoneId.of("UTC");
}
public LocalDate asDate() {
return LocalDate.now();
}
}
@Test
public void testInvalidCombination1() throws Throwable {
Invalid1 proxyOuter = new Invalid1();
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertInvalidState(() -> INTEROP.asDate(proxyInner));
assertInvalidState(() -> INTEROP.asTimeZone(proxyInner));
assertInvalidState(() -> INTEROP.isDate(proxyInner));
assertInvalidState(() -> INTEROP.isTimeZone(proxyInner));
}
static class Invalid2 implements ProxyTime, ProxyTimeZone {
public ZoneId asTimeZone() {
return ZoneId.of("US/Pacific");
}
public LocalTime asTime() {
return LocalTime.now();
}
}
@Test
public void testInvalidCombination2() throws Throwable {
Invalid2 proxyOuter = new Invalid2();
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertInvalidState(() -> INTEROP.asTime(proxyInner));
assertInvalidState(() -> INTEROP.asTimeZone(proxyInner));
assertInvalidState(() -> INTEROP.isTime(proxyInner));
assertInvalidState(() -> INTEROP.isTimeZone(proxyInner));
}
@SuppressWarnings("serial")
static class TestError extends RuntimeException {
TestError() {
super("Host Error");
}
}
@SuppressWarnings("deprecation")
private static class AllProxy implements ProxyArray, ProxyObject, ProxyNativeObject, ProxyExecutable, ProxyInstantiable {
public Object execute(Value... t) {
throw new TestError();
}
@Override
public Object newInstance(Value... arguments) {
throw new TestError();
}
public long asPointer() {
throw new TestError();
}
public Object getMember(String key) {
throw new TestError();
}
public ProxyArray getMemberKeys() {
throw new TestError();
}
public boolean hasMember(String key) {
throw new TestError();
}
public void putMember(String key, Value value) {
throw new TestError();
}
@Override
public boolean remove(long index) {
throw new TestError();
}
@Override
public boolean removeMember(String key) {
throw new TestError();
}
public Object get(long index) {
throw new TestError();
}
public void set(long index, Value value) {
throw new TestError();
}
public long getSize() {
throw new TestError();
}
}
@Test
public void testProxyError() throws Throwable {
Proxy proxyOuter = new AllProxy();
TruffleObject proxyInner = toInnerProxy(proxyOuter);
assertHostError(() -> INTEROP.execute(proxyInner));
assertHostError(() -> INTEROP.asPointer(proxyInner));
assertHostError(() -> INTEROP.getArraySize(proxyInner));
assertHostError(() -> INTEROP.getMembers(proxyInner));
assertHostError(() -> INTEROP.readMember(proxyInner, ""));
assertHostError(() -> INTEROP.writeMember(proxyInner, "", ""));
assertHostError(() -> INTEROP.removeMember(proxyInner, ""));
assertHostError(() -> INTEROP.readArrayElement(proxyInner, 0));
assertHostError(() -> INTEROP.removeArrayElement(proxyInner, 0));
assertHostError(() -> INTEROP.writeArrayElement(proxyInner, 0, ""));
INTEROP.toNative(proxyInner);
assertHostError(() -> INTEROP.invokeMember(proxyInner, ""));
assertHostError(() -> INTEROP.execute(proxyInner));
assertHostError(() -> INTEROP.instantiate(proxyInner));
assertHostError(() -> INTEROP.isMemberReadable(proxyInner, ""));
assertHostError(() -> INTEROP.isMemberModifiable(proxyInner, ""));
assertHostError(() -> INTEROP.isMemberInsertable(proxyInner, ""));
assertHostError(() -> INTEROP.isMemberRemovable(proxyInner, ""));
assertHostError(() -> INTEROP.isMemberInvocable(proxyInner, ""));
assertFalse(INTEROP.isMemberInternal(proxyInner, ""));
assertHostError(() -> INTEROP.isArrayElementReadable(proxyInner, 0L));
assertHostError(() -> INTEROP.isArrayElementModifiable(proxyInner, 0L));
assertHostError(() -> INTEROP.isArrayElementInsertable(proxyInner, 0L));
assertHostError(() -> INTEROP.isArrayElementRemovable(proxyInner, 0L));
assertFalse(INTEROP.isNumber(proxyInner));
assertTrue(INTEROP.isExecutable(proxyInner));
assertTrue(INTEROP.isInstantiable(proxyInner));
assertFalse(INTEROP.isNull(proxyInner));
assertTrue(INTEROP.hasMembers(proxyInner));
assertTrue(INTEROP.hasArrayElements(proxyInner));
assertTrue(INTEROP.isPointer(proxyInner));
}
private static void assertEmpty(Object proxyInner) {
try {
assertTrue(INTEROP.hasArrayElements(proxyInner));
assertEquals(0L, INTEROP.getArraySize(proxyInner));
} catch (InteropException e) {
Assert.fail();
}
}
private void assertHostError(InteropCallable r) {
try {
r.call();
Assert.fail();
} catch (InteropException e) {
Assert.fail();
} catch (RuntimeException e) {
InteropLibrary interop = InteropLibrary.getUncached();
Assert.assertTrue(interop.isException(e));
Assert.assertEquals("Host Error", ((Exception) e).getMessage());
Assert.assertTrue(languageEnv.asHostException(e) instanceof TestError);
}
}
private static void assertInvalidState(InteropCallable r) {
boolean valid = true;
try {
r.call();
valid = false;
} catch (InteropException e) {
Assert.fail();
} catch (AssertionError e) {
}
if (!valid) {
throw new AssertionError("assertion expected");
}
}
interface InteropCallable {
void call() throws InteropException;
}
private static void assertUnsupported(InteropCallable r) throws Exception {
try {
r.call();
Assert.fail();
} catch (UnsupportedMessageException e) {
} catch (InteropException e) {
throw e;
}
}
private static void assertInvalidArrayIndex(InteropCallable r) throws Exception {
try {
r.call();
Assert.fail();
} catch (InvalidArrayIndexException e) {
} catch (InteropException e) {
throw e;
}
}
}