package com.oracle.truffle.js.test.instrumentation.sourcesections;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.stream.Collectors;
import org.graalvm.polyglot.PolyglotException;
import org.junit.After;
import org.junit.Before;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.EventContext;
import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
import com.oracle.truffle.api.instrumentation.StandardTags.ExpressionTag;
import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag;
import com.oracle.truffle.js.test.instrumentation.FineGrainedAccessTest;
import com.oracle.truffle.js.test.instrumentation.TestUtil;
import com.oracle.truffle.js.test.instrumentation.TestingExecutionInstrument;
public class SourceSectionInstrumentationTest extends FineGrainedAccessTest {
private ArrayList<CharSequence> sources = new ArrayList<>();
private void initStatementInstrument(int maxEvents) {
SourceSectionFilter stmFilter = SourceSectionFilter.newBuilder().tagIs(StatementTag.class).includeInternal(false).build();
instrumenter.attachExecutionEventListener(stmFilter, new ExecutionEventListener() {
@Override
public void onEnter(EventContext cx, VirtualFrame frame) {
if (sources.size() < maxEvents) {
sources.add(cx.getInstrumentedSourceSection().getCharacters());
}
}
@Override
public void onReturnValue(EventContext cx, VirtualFrame frame, Object result) {
}
@Override
public void onReturnExceptional(EventContext cx, VirtualFrame frame, Throwable exception) {
}
});
}
protected void evalStatements(String src) {
initStatementInstrument(Integer.MAX_VALUE);
context.eval("js", src);
}
protected void evalMaxStatementsTimeout(String src, int maxEvents, int timeout) {
initStatementInstrument(maxEvents);
context.initialize("js");
Timer timer = new Timer(true);
timer.schedule(new TimerTask() {
@Override
public void run() {
context.close(true);
}
}, timeout);
try {
context.eval("js", src);
assert false;
} catch (PolyglotException e) {
assert e.isCancelled();
}
}
protected void evalExpressions(String src) {
SourceSectionFilter expFilter = SourceSectionFilter.newBuilder().tagIs(ExpressionTag.class).includeInternal(false).build();
instrumenter.attachExecutionEventListener(expFilter, new ExecutionEventListener() {
@Override
public void onEnter(EventContext cx, VirtualFrame frame) {
}
@Override
public void onReturnValue(EventContext cx, VirtualFrame frame, Object result) {
sources.add(cx.getInstrumentedSourceSection().getCharacters());
}
@Override
public void onReturnExceptional(EventContext cx, VirtualFrame frame, Throwable exception) {
}
});
context.eval("js", src);
}
public final void assertSourceSections(String[] expected) {
int i = 0;
assertEquals(sources.stream().collect(Collectors.joining("\n")), expected.length, sources.size());
for (String s : expected) {
assertEquals(s, sources.get(i++));
}
}
@After
@Override
public void disposeAgent() {
assertTrue(!sources.isEmpty());
context.leave();
sources.clear();
}
@Override
@Before
public void initTest() {
context = TestUtil.newContextBuilder().build();
instrument = context.getEngine().getInstruments().get(TestingExecutionInstrument.ID).lookup(TestingExecutionInstrument.class);
instrumenter = instrument.getEnvironment().getInstrumenter();
sources = new ArrayList<>();
context.enter();
}
}