package com.oracle.truffle.api.test.polyglot;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.graalvm.polyglot.Context;
import org.junit.Test;
import org.junit.runners.Parameterized.Parameters;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
import com.oracle.truffle.api.instrumentation.ProbeNode;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.interop.InteropLibrary;
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;
import com.oracle.truffle.api.nodes.LanguageInfo;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.test.AbstractParametrizedLibraryTest;
@SuppressWarnings("deprecation")
public class ScopedViewLegacyTest extends AbstractParametrizedLibraryTest {
@Parameters(name = "{0}")
public static List<TestRun> data() {
return Arrays.asList(TestRun.CACHED, TestRun.UNCACHED, TestRun.DISPATCHED_CACHED, TestRun.DISPATCHED_UNCACHED);
}
@ExportLibrary(InteropLibrary.class)
static class OtherScopedLanguageLegacyObject implements TruffleObject {
@ExportMessage
boolean hasLanguage() {
return true;
}
@ExportMessage
Class<? extends TruffleLanguage<?>> getLanguage() {
return OtherTestLanguage.class;
}
@SuppressWarnings("static-method")
@ExportMessage
final Object toDisplayString(@SuppressWarnings("unused") boolean allowSideEffects) {
return "other";
}
}
static class TestInstrumentableNode extends Node implements InstrumentableNode {
private final Class<? extends Tag> tag;
TestInstrumentableNode() {
this.tag = null;
}
TestInstrumentableNode(Class<? extends Tag> tag) {
this.tag = tag;
}
@Override
public boolean isInstrumentable() {
return true;
}
@Override
public WrapperNode createWrapper(ProbeNode probe) {
return null;
}
@Override
public boolean hasTag(Class<? extends Tag> t) {
return t == this.tag;
}
}
static class TestOtherNode extends Node {
}
static class TestNotInstrumentableNode extends Node implements InstrumentableNode {
public boolean isInstrumentable() {
return false;
}
public WrapperNode createWrapper(ProbeNode probe) {
return null;
}
}
static class TestRootNode extends RootNode {
protected TestRootNode(TruffleLanguage<?> language) {
super(language);
}
@Child Node child;
public void setChild(Node child) {
this.child = insert(child);
}
@Override
public Object execute(VirtualFrame frame) {
return null;
}
}
static TestRootNode createRoot(TruffleLanguage<?> lang) {
TestRootNode root = new TestRootNode(lang);
Truffle.getRuntime().createCallTarget(new TestRootNode(lang));
return root;
}
@Test
public void testValidRequest() throws UnsupportedMessageException {
AtomicInteger count = new AtomicInteger();
setupEnv(Context.create(), new ProxyLanguage() {
@Override
protected Object getScopedView(LanguageContext c, Node location, Frame frame, Object value) {
count.incrementAndGet();
try {
assertSame(ProxyLanguage.class, createLibrary(InteropLibrary.class, value).getLanguage(value));
} catch (UnsupportedMessageException e) {
fail();
}
return super.getScopedView(c, location, frame, value);
}
});
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
Object scopedView = instrumentEnv.getScopedView(l, location, frame, "");
assertSame(ProxyLanguage.class, createLibrary(InteropLibrary.class, scopedView).getLanguage(scopedView));
assertEquals(1, count.get());
}
@Test
public void testWrongRootLanguage() {
setupEnv();
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(null);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testUnadoptedNode() {
setupEnv();
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(language);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testNotInstrumentable() {
setupEnv();
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestNotInstrumentableNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testOtherNode() {
setupEnv();
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestOtherNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testInvalidFrame() {
setupEnv();
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], createRoot(language).getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testWrongLanguage() {
setupEnv();
context.initialize(OtherTestLanguage.ID);
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(OtherTestLanguage.getInstance());
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], createRoot(language).getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), IllegalArgumentException.class);
}
@Test
public void testReturnWrongLanguage() {
setupEnv(Context.create(), new ProxyLanguage() {
@Override
protected Object getScopedView(LanguageContext c, Node location, Frame frame, Object value) {
return new OtherScopedLanguageLegacyObject();
}
});
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), AssertionError.class);
}
@Test
public void testReturnNull() {
setupEnv(Context.create(), new ProxyLanguage() {
@Override
protected Object getScopedView(LanguageContext c, Node location, Frame frame, Object value) {
return null;
}
});
LanguageInfo l = instrumentEnv.getLanguages().get(ProxyLanguage.ID);
Node location = new TestInstrumentableNode();
TestRootNode root = createRoot(language);
root.setChild(location);
Frame frame = Truffle.getRuntime().createVirtualFrame(new Object[0], root.getRootNode().getFrameDescriptor());
assertFails(() -> instrumentEnv.getScopedView(l, location, frame, ""), AssertionError.class);
}
}