You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by en...@apache.org on 2022/02/11 09:25:07 UTC

[netbeans] branch master updated: Integration tests of Truffle/Graal scripts debugger.

This is an automated email from the ASF dual-hosted git repository.

entl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new aa1f69f  Integration tests of Truffle/Graal scripts debugger.
aa1f69f is described below

commit aa1f69f3fb50defdda5aab682275d35be49557fa
Author: Martin Entlicher <ma...@oracle.com>
AuthorDate: Sun Feb 6 11:22:23 2022 +0100

    Integration tests of Truffle/Graal scripts debugger.
---
 .../nbproject/project.properties                   |   1 +
 java/debugger.jpda.truffle/nbproject/project.xml   |  23 ++
 .../debugger/jpda/truffle/TruffleDebugManager.java |   5 +-
 .../impl/TruffleBreakpointsHandler.java            |   2 +
 .../debugger/jpda/truffle/DebugAllBaseTest.java    | 247 +++++++++++++++++++++
 .../modules/debugger/jpda/truffle/DebugJSTest.java |  99 +++++++++
 .../debugger/jpda/truffle/DebugPythonTest.java     |  87 ++++++++
 .../modules/debugger/jpda/truffle/DebugRTest.java  |  86 +++++++
 .../debugger/jpda/truffle/DebugRubyTest.java       | 101 +++++++++
 .../modules/debugger/jpda/truffle/DebugSLTest.java | 193 ----------------
 .../debugger/jpda/truffle/JPDATestCase.java        | 144 ++++++++++++
 .../debugger/jpda/truffle/PolyglotTest.java        | 194 ++++++++++++++++
 .../TestApp.sl => scripts/DebuggerBase.js}         |  35 ++-
 .../debugger/jpda/truffle/scripts/DebuggerBase.py} |  41 +++-
 .../debugger/jpda/truffle/scripts/DebuggerBase.r}  |  41 +++-
 .../jpda/truffle/scripts/DebuggerBase.ruby}        |  41 +++-
 .../{testapps/TestApp.sl => scripts/Types.js}      |  47 +++-
 .../debugger/jpda/truffle/scripts/Types.py}        |  33 ++-
 .../modules/debugger/jpda/truffle/scripts/Types.r} |  33 ++-
 .../debugger/jpda/truffle/scripts/Types.ruby}      |  43 +++-
 .../debugger/jpda/truffle/scripts/Weather.js       | 124 +++++++++++
 .../debugger/jpda/truffle/scripts/Weather.py}      |  28 ++-
 .../debugger/jpda/truffle/scripts/Weather.r        |  56 +++++
 .../debugger/jpda/truffle/scripts/Weather.rb}      |  21 +-
 ...{SLAppFromFile.java => PolyglotWeatherApp.java} |  25 +--
 .../debugger/jpda/truffle/testapps/SLApp.java      |  65 ------
 .../jpda/truffle/testapps/WeatherCity.java         |  52 +++++
 .../jpda/truffle/testapps/WeatherCityService.java  |  67 ++++++
 .../jpda/backend/truffle/JPDATruffleAccessor.java  |   1 +
 .../netbeans/api/debugger/jpda/JPDASupport.java    | 148 ++++++++----
 nbbuild/travis/scripting.sh                        |   2 +
 31 files changed, 1684 insertions(+), 401 deletions(-)

diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/nbproject/project.properties
index adfab1c..3d3ba96 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/nbproject/project.properties
@@ -23,4 +23,5 @@ requires.nb.javac=true
 truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
 cp.extra=${tools.jar}:${truffle.sl}
 test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
+test-unit-sys-prop.test.dir.classes=${basedir}/build/test/unit/classes
 test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
diff --git a/java/debugger.jpda.truffle/nbproject/project.xml b/java/debugger.jpda.truffle/nbproject/project.xml
index f15d913..3d345ab 100644
--- a/java/debugger.jpda.truffle/nbproject/project.xml
+++ b/java/debugger.jpda.truffle/nbproject/project.xml
@@ -259,12 +259,35 @@
                 <test-type>
                     <name>unit</name>
                     <test-dependency>
+                        <code-name-base>org.netbeans.core.startup</code-name-base>
+                        <recursive/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.libs.freemarker</code-name-base>
+                        <recursive/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.libs.javacapi</code-name-base>
+                        <recursive/>
+                    </test-dependency>
+                    <test-dependency>
                         <code-name-base>org.netbeans.modules.debugger.jpda</code-name-base>
+			<compile-dependency/>
+                        <test/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.api.debugger.jpda</code-name-base>
+                        <recursive/>
                         <compile-dependency/>
                         <test/>
                     </test-dependency>
+		    <test-dependency>
+                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
                     <test-dependency>
                         <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
+                        <recursive/>
                         <compile-dependency/>
                     </test-dependency>
                 </test-type>
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
index 01f209f..14aa3f0 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/TruffleDebugManager.java
@@ -146,7 +146,9 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
             @Override
             public void breakpointReached(JPDABreakpointEvent event) {
                 try {
-                    handleEngineBuilder(debugger, event);
+                    if (event.getDebugger() == debugger) {
+                        handleEngineBuilder(debugger, event);
+                    }
                 } finally {
                     event.resume();
                 }
@@ -193,6 +195,7 @@ public class TruffleDebugManager extends DebuggerManagerAdapter {
         builderExitBreakpoint.setBreakpointType(MethodBreakpoint.TYPE_METHOD_EXIT);
         builderExitBreakpoint.setThreadFilters(debugger, new JPDAThread[]{entryEvent.getThread()});
         builderExitBreakpoint.setSuspend(JPDABreakpoint.SUSPEND_EVENT_THREAD);
+        builderExitBreakpoint.setSession(debugger);
         builderExitBreakpoint.setHidden(true);
         builderExitBreakpoint.addJPDABreakpointListener(exitEvent -> {
             try {
diff --git a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
index ce0c05a..606b9b0 100644
--- a/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
+++ b/java/debugger.jpda.truffle/src/org/netbeans/modules/debugger/jpda/truffle/breakpoints/impl/TruffleBreakpointsHandler.java
@@ -262,6 +262,7 @@ public class TruffleBreakpointsHandler {
                     setLineBreakpointMethod,
                     args,
                     ObjectReference.INVOKE_SINGLE_THREADED);
+            ret.disableCollection();
             return ret;
         } catch (VMDisconnectedExceptionWrapper | InternalExceptionWrapper |
                  ClassNotLoadedException | ClassNotPreparedExceptionWrapper |
@@ -396,6 +397,7 @@ public class TruffleBreakpointsHandler {
                                 Exceptions.printStackTrace(ex);
                             }
                             TruffleBreakpointsRegistry.getDefault().remove(debugger, bpImpl);
+                            bpImpl.enableCollection();
                         }
                     } catch (VMDisconnectedExceptionWrapper ex) {}
                 }
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugAllBaseTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugAllBaseTest.java
new file mode 100644
index 0000000..8819f0b
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugAllBaseTest.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import java.net.URL;
+import junit.framework.Test;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.Variable;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+
+public class DebugAllBaseTest extends JPDATestCase {
+
+    private static final String SCRIPT_NAME = "DebuggerBase";
+    private static final String[] SCRIPT_EXTENSIONS = { "js", "py", "r", "ruby" };
+    private static final String[] LAUNCHERS = { "js", "graalpython", "Rscript", "ruby" };
+
+    public DebugAllBaseTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(DebugAllBaseTest.class);
+    }
+
+    private void forAllScripts(ThrowableBiConsumer<String, File> scriptConsumer) {
+        for (int i = 0; i < LAUNCHERS.length; i++) {
+            String launcher = LAUNCHERS[i];
+            File source = getScriptSourceFile(SCRIPT_NAME + "." + SCRIPT_EXTENSIONS[i]);
+            try {
+                scriptConsumer.accept(launcher, source);
+            } catch (Throwable t) {
+                throw new AssertionError(launcher + " " + source, t);
+            }
+        }
+    }
+
+    public void testBreakpoints() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            URL url = source.toURI().toURL();
+            JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, 25);
+            dm.addBreakpoint(lb1);
+            JSLineBreakpoint lb2 = new TruffleLineBreakpoint(url, 29);
+            dm.addBreakpoint(lb2);
+            String sourcePath = source.getAbsolutePath();
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 25);
+                support.doContinue();
+                support.waitState(JPDADebugger.STATE_STOPPED);
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 29);
+                dm.removeBreakpoint(lb2);
+                support.doContinue();
+            });
+        });
+    }
+
+    public void testBreakpointsConditional() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            String and;
+            switch (launcher) {
+                case "js": and = "&&"; break;
+                case "Rscript": and = "&"; break;
+                default: and = "and";
+            }
+            String condition = "n == 2 " + and + " n1 == 3";
+            URL url = source.toURI().toURL();
+            JSLineBreakpoint lb = new TruffleLineBreakpoint(url, 35);
+            lb.setCondition(condition);
+            dm.addBreakpoint(lb);
+            String sourcePath = source.getAbsolutePath();
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                // The conditional breakpoint is hit two times:
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 35);
+                support.doContinue();
+                support.waitState(JPDADebugger.STATE_STOPPED);
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 35);
+                support.doContinue();
+            });
+        });
+    }
+
+    public void testSteps() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            URL url = source.toURI().toURL();
+            String sourcePath = source.getAbsolutePath();
+            JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, 42);
+            dm.addBreakpoint(lb1);
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 42);
+                support.stepOver();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 43);
+                support.stepInto();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 23);
+                support.stepOut();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 43);
+                support.doContinue();
+            });
+        });
+    }
+
+    public void testEval() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            URL url = source.toURI().toURL();
+            String sourcePath = source.getAbsolutePath();
+            JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, 29);
+            dm.addBreakpoint(lb1);
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 29);
+                // a = 20
+                Variable v = debugger.evaluate("a");
+                TruffleVariable tv = TruffleVariable.get(v);
+                assertTrue(tv.getDisplayValue(), tv.getDisplayValue().contains("20"));
+                // o.ao = "AO"
+                String expr;
+                switch (launcher) {
+                    case "ruby": expr = "o.instance_variable_get :@ao"; break;
+                    case "Rscript": expr = "o[\"ao\"]"; break;
+                    default: expr = "o.ao";
+                }
+                v = debugger.evaluate(expr);
+                tv = TruffleVariable.get(v);
+                assertTrue(tv.getDisplayValue(), tv.getDisplayValue().contains("AO"));
+                // arr[1] + arr[2]
+                v = debugger.evaluate("arr[1] + arr[2]");
+                tv = TruffleVariable.get(v);
+                String result = launcher.equals("Rscript") ? "9" : "7"; // Arrays start at index 1 in R
+                assertTrue(tv.getDisplayValue(), tv.getDisplayValue().contains(result));
+                support.doContinue();
+            });
+        });
+    }
+
+    public void testLocalVariables() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            URL url = source.toURI().toURL();
+            String sourcePath = source.getAbsolutePath();
+            JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, 23);
+            dm.addBreakpoint(lb1);
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 23);
+                if (launcher.equals("Rscript") && frame.getScopes().length == 0) {
+                    support.doContinue();
+                    return;
+                }
+                TruffleScope scope = frame.getScopes()[0];
+                if (launcher.equals("js")) {
+                    assertNull("a is not visible yet", findVariable(scope, "a"));
+                    assertNull("o is not visible yet", findVariable(scope, "o"));
+                    assertNull("arr is not visible yet", findVariable(scope, "arr"));
+                }
+                support.stepOver();
+                scope = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 24).getScopes()[0];
+                assertNotNull("a is visible", findVariable(scope, "a"));
+                if (launcher.equals("js")) {
+                    assertNull("o is not visible yet", findVariable(scope, "o"));
+                    assertNull("arr is not visible yet", findVariable(scope, "arr"));
+                }
+                support.stepOver();
+                scope = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 25).getScopes()[0];
+                assertNotNull("a is visible", findVariable(scope, "a"));
+                assertNotNull("o is visible", findVariable(scope, "o"));
+                if (launcher.equals("js")) {
+                    assertNull("arr is not visible yet", findVariable(scope, "arr"));
+                }
+                support.stepOver();
+                support.stepOver();
+                scope = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 27).getScopes()[0];
+                assertNotNull("a is visible", findVariable(scope, "a"));
+                assertNotNull("o is visible", findVariable(scope, "o"));
+                assertNotNull("arr is visible", findVariable(scope, "arr"));
+                support.doContinue();
+            });
+        });
+    }
+
+    public void testObjectProperties() {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        forAllScripts((launcher, source) -> {
+            URL url = source.toURI().toURL();
+            String sourcePath = source.getAbsolutePath();
+            JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, 29);
+            dm.addBreakpoint(lb1);
+            runScriptUnderJPDA(launcher, source.getAbsolutePath(), support -> {
+                JPDADebugger debugger = support.getDebugger();
+                TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, 29);
+                TruffleVariable o = findVariable(frame.getScopes()[0], "o");
+                assertNotNull("Variable o not found!", o);
+                Object[] children = o.getChildren();
+                String aoName = launcher.equals("ruby") ? "@ao" : "ao";
+                boolean hasAO = false;
+                for (Object ch : children) {
+                    if (ch instanceof TruffleVariable && ((TruffleVariable) ch).getName().equals(aoName)) {
+                        hasAO = true;
+                        break;
+                    }
+                }
+                StringBuilder chstr = new StringBuilder("(" + children.length + ")");
+                if (!hasAO) {
+                    for (Object ch : children) {
+                        chstr.append(ch.getClass().getName());
+                        chstr.append('{');
+                        if (ch instanceof TruffleVariable) {
+                            chstr.append(((TruffleVariable) ch).getName());
+                            chstr.append(": ");
+                            chstr.append(((TruffleVariable) ch).getValue());
+                        }
+                        chstr.append('}');
+                    }
+                }
+                assertTrue("AO child was not found, children = " + chstr, hasAO);
+                support.doContinue();
+            });
+        });
+    }
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugJSTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugJSTest.java
new file mode 100644
index 0000000..f270781
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugJSTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import junit.framework.Test;
+import static junit.framework.TestCase.assertEquals;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+
+public class DebugJSTest extends JPDATestCase {
+
+    public DebugJSTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(DebugJSTest.class);
+    }
+
+    public void testJSTypes() throws Exception {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        File source = new File(sourceRoot, "org/netbeans/modules/debugger/jpda/truffle/scripts/Types.js");
+        String sourcePath = source.getAbsolutePath();
+        int debugLine = 51;
+        String methodName = "typesTest";
+        runScriptUnderJPDA("js", source.getAbsolutePath(), support -> {
+            JPDADebugger debugger = support.getDebugger();
+            TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, debugLine);
+            assertEquals("Bad method name", methodName, frame.getMethodName());
+            checkVariableTypes(frame.getScopes());
+            support.doContinue();
+        });
+    }
+
+    private static void checkVariableTypes(TruffleScope[] scopes) {
+        assertEquals(1, scopes.length);
+        TruffleVariable[] variables = scopes[0].getVariables();
+        assertEquals("this", variables[0].getName());
+        checkVar(variables[1], "a1", "Array", "[]");
+        checkVar(variables[2], "a2", "Array", "(3)[1, 2, [3, 4]]");
+
+        checkVar(variables[3], "b1", "boolean", "true");
+        checkVar(variables[4], "b2", "boolean", "false");
+
+        checkVar(variables[5], "c1", "TestClass", "{}");
+
+        checkVar(variables[6], "i1", "number", "0");
+        checkVar(variables[7], "i2", "number", "42");
+        checkVar(variables[8], "i3", "number", "42.42");
+        checkVar(variables[9], "i4", "number", "-0");
+        checkVar(variables[10], "i5", "number", "-Infinity");
+        checkVar(variables[11], "i6", "number", "Infinity");
+        checkVar(variables[12], "i7", "number", "-Infinity");
+        checkVar(variables[13], "i8", "number", "NaN");
+
+        checkVar(variables[14], "aSparse", "Array", null/*"(11)[1, 2, empty × 8, 10]"*/);
+        assertTrue(variables[14].getValue().toString(), variables[14].getValue().toString().startsWith("(11)[")); // Do not rely on the exact format
+        checkVar(variables[15], "s1", "string", "String");
+        checkVar(variables[16], "f1", "pow2", null);
+        assertTrue(variables[16].getValue().toString(), variables[16].getValue().toString().startsWith("function pow2(x)"));
+        checkVar(variables[17], "d1", "Date", null);
+        checkVar(variables[18], "undef", "undefined", "undefined");
+        checkVar(variables[19], "nul", "null", "null");
+        checkVar(variables[20], "sy", "symbol", "Symbol(symbolic)");
+        checkVar(variables[21], "o1", "Object", "{}");
+        checkVar(variables[22], "o2", "TestFncProp", "{fncProp: \"Property\", a: \"A\"}");
+        checkVar(variables[23], "map", "Map", null);
+    }
+
+    private static void checkVar(TruffleVariable variable, String name, String type, String value) {
+        assertEquals("Name", name, variable.getName());
+        assertEquals("Type of " + name, type, variable.getType());
+        if (value != null) {
+            assertEquals("Value of " + name, value, variable.getValue());
+        }
+    }
+
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugPythonTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugPythonTest.java
new file mode 100644
index 0000000..7f1b1a0
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugPythonTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import java.net.URL;
+import junit.framework.Test;
+import static junit.framework.TestCase.assertEquals;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+
+public class DebugPythonTest extends JPDATestCase {
+
+    public DebugPythonTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(DebugPythonTest.class);
+    }
+
+    public void testPythonTypes() throws Exception {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        File source = new File(sourceRoot, "org/netbeans/modules/debugger/jpda/truffle/scripts/Types.py");
+        URL url = source.toURI().toURL();
+        String sourcePath = source.getAbsolutePath();
+        int debugLine = 39;
+        String methodName = "typesTest";
+        JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, debugLine);
+        dm.addBreakpoint(lb1);
+        runScriptUnderJPDA("graalpython", source.getAbsolutePath(), support -> {
+            JPDADebugger debugger = support.getDebugger();
+            TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, debugLine);
+            assertEquals("Bad method name", methodName, frame.getMethodName());
+            checkVariableTypes(frame.getScopes());
+            support.doContinue();
+        });
+    }
+
+    private static void checkVariableTypes(TruffleScope[] scopes) {
+        assertTrue(scopes.length >= 1);
+        TruffleVariable[] variables = scopes[0].getVariables();
+        checkVar(variables[0], "a", "list", "[1, 2, 3, 42]");
+
+        checkVar(variables[1], "b1", "bool", "True");
+        checkVar(variables[2], "b2", "bool", "False");
+
+        checkVar(variables[3], "i", "int", "42");
+        checkVar(variables[4], "s", "str", "'string'");
+        checkVar(variables[5], "n", "NoneType", "None");
+        checkVar(variables[6], "f", "function", null);
+        assertTrue(variables[6].getValue().toString(), variables[6].getValue().toString().contains("Callable"));
+        checkVar(variables[7], "d", "datetime", null);
+        checkVar(variables[8], "map", "dict", null);
+    }
+
+    private static void checkVar(TruffleVariable variable, String name, String type, String value) {
+        assertEquals("Name", name, variable.getName());
+        assertEquals("Type of " + name, type, variable.getType());
+        if (value != null) {
+            assertEquals("Value of " + name, value, variable.getValue());
+        }
+    }
+
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRTest.java
new file mode 100644
index 0000000..c209c55
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import java.net.URL;
+import junit.framework.Test;
+import static junit.framework.TestCase.assertEquals;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+
+public class DebugRTest extends JPDATestCase {
+
+    public DebugRTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(DebugRTest.class);
+    }
+
+    public void testRTypes() throws Exception {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        File source = new File(sourceRoot, "org/netbeans/modules/debugger/jpda/truffle/scripts/Types.r");
+        URL url = source.toURI().toURL();
+        String sourcePath = source.getAbsolutePath();
+        int debugLine = 38;
+        String methodName = "typesTest";
+        JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, debugLine);
+        dm.addBreakpoint(lb1);
+        runScriptUnderJPDA("Rscript", source.getAbsolutePath(), support -> {
+            JPDADebugger debugger = support.getDebugger();
+            TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, debugLine);
+            assertTrue("Bad method name: " + frame.getMethodName(), frame.getMethodName().contains(methodName));
+            checkVariableTypes(frame.getScopes());
+            support.doContinue();
+        });
+    }
+
+    private static void checkVariableTypes(TruffleScope[] scopes) {
+        assertEquals(1, scopes.length);
+        TruffleVariable[] variables = scopes[0].getVariables();
+
+        checkVar(variables[0], "a", "double", "[1]  1  2  3 42");
+        checkVar(variables[1], "b1", "logical", "[1] TRUE");
+        checkVar(variables[2], "b2", "logical", "[1] FALSE");
+
+        checkVar(variables[3], "i", "double", "[1] 42");
+        checkVar(variables[4], "s", "character", "[1] \"string\"");
+        checkVar(variables[5], "n", "NULL", "NULL");
+        checkVar(variables[6], "f", "closure", "function() {\n\n}");
+        checkVar(variables[7], "d", "double", null);
+        checkVar(variables[8], "map", "environment", null);
+    }
+
+    private static void checkVar(TruffleVariable variable, String name, String type, String value) {
+        assertEquals("Name", name, variable.getName());
+        assertEquals("Type of " + name, type, variable.getType());
+        if (value != null) {
+            assertEquals("Value of " + name, value, variable.getValue());
+        }
+    }
+
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRubyTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRubyTest.java
new file mode 100644
index 0000000..1f253c6
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugRubyTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import java.net.URL;
+import junit.framework.Test;
+import static junit.framework.TestCase.assertEquals;
+
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.netbeans.modules.javascript2.debug.breakpoints.JSLineBreakpoint;
+
+public class DebugRubyTest extends JPDATestCase {
+
+    public DebugRubyTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(DebugRubyTest.class);
+    }
+
+    public void testRubyTypes() throws Exception {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        File source = new File(sourceRoot, "org/netbeans/modules/debugger/jpda/truffle/scripts/Types.ruby");
+        URL url = source.toURI().toURL();
+        String sourcePath = source.getAbsolutePath();
+        int debugLine = 46;
+        String methodName = "typesTest";
+        JSLineBreakpoint lb1 = new TruffleLineBreakpoint(url, debugLine);
+        dm.addBreakpoint(lb1);
+        runScriptUnderJPDA("ruby", source.getAbsolutePath(), support -> {
+            JPDADebugger debugger = support.getDebugger();
+            TruffleStackFrame frame = checkStoppedAtScript(debugger.getCurrentThread(), sourcePath, debugLine);
+            assertTrue("Bad method name: " + frame.getMethodName(), frame.getMethodName().contains(methodName));
+            checkVariableTypes(frame.getScopes());
+            support.doContinue();
+        });
+    }
+
+    private static void checkVariableTypes(TruffleScope[] scopes) {
+        assertEquals(1, scopes.length);
+        TruffleVariable[] variables = scopes[0].getVariables();
+        assertEquals("self", variables[0].getName());
+        checkVar(variables[1], "a1", "Array", "[]");
+        checkVar(variables[2], "a2", "Array", "[1, 2, [3, 4]]");
+
+        checkVar(variables[3], "b1", "", "true");
+        checkVar(variables[4], "b2", "", "false");
+
+        checkVar(variables[5], "null", "NilClass", "nil");
+
+        checkVar(variables[6], "i1", "", "0");
+        checkVar(variables[7], "i2", "", "42");
+        checkVar(variables[8], "i3", "", "42.42");
+        checkVar(variables[9], "i4", "", "-0.0");
+        checkVar(variables[10], "i5", "", "-Infinity");
+        checkVar(variables[11], "i6", "", "Infinity");
+        checkVar(variables[12], "i7", "", "-Infinity");
+        checkVar(variables[13], "i8", "", "NaN");
+
+        checkVar(variables[14], "nc", "Complex", "(2+3i)");
+        checkVar(variables[15], "nr", "Rational", "(11/2)");
+        checkVar(variables[16], "f", "Method", null);
+        assertTrue(variables[16].getValue().toString(), variables[16].getValue().toString().contains("Callable"));
+        checkVar(variables[17], "d", "Time", null);
+        checkVar(variables[18], "str", "String", "\"A String\"");
+        checkVar(variables[19], "symbol", "Symbol", ":symbolic");
+        checkVar(variables[20], "hash", "Hash", "{:a=>1, \"b\"=>2}");
+    }
+
+    private static void checkVar(TruffleVariable variable, String name, String type, String value) {
+        assertEquals("Name", name, variable.getName());
+        assertEquals("Type of " + name, type, variable.getType());
+        if (value != null) {
+            assertEquals("Value of " + name, value, variable.getValue());
+        }
+    }
+
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
deleted file mode 100644
index 94e0f43..0000000
--- a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/DebugSLTest.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.netbeans.modules.debugger.jpda.truffle;
-
-import com.oracle.truffle.api.TruffleLanguage;
-import com.oracle.truffle.sl.SLLanguage;
-import java.io.File;
-import java.lang.reflect.Field;
-import java.net.URISyntaxException;
-import java.net.URL;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import org.graalvm.polyglot.Engine;
-import org.netbeans.api.debugger.DebuggerManager;
-import org.netbeans.api.debugger.jpda.CallStackFrame;
-import org.netbeans.api.debugger.jpda.JPDADebugger;
-import org.netbeans.api.debugger.jpda.JPDASupport;
-import org.netbeans.api.debugger.jpda.LineBreakpoint;
-import org.netbeans.junit.NbTestCase;
-import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
-import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
-import org.netbeans.modules.debugger.jpda.truffle.access.TruffleStrataProvider;
-import org.netbeans.modules.debugger.jpda.truffle.breakpoints.TruffleLineBreakpoint;
-import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
-import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
-import org.netbeans.modules.javascript2.debug.EditorLineHandlerFactory;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.URLMapper;
-
-public class DebugSLTest extends NbTestCase {
-    private DebuggerManager dm = DebuggerManager.getDebuggerManager();
-    private final String sourceRoot = System.getProperty("test.dir.src");
-    private JPDASupport support;
-
-    public DebugSLTest(String name) {
-        super(name);
-    }
-
-    public static Test suite() throws URISyntaxException {
-        final File sdkAPI = new File(Engine.class.getProtectionDomain().getCodeSource().getLocation().toURI());
-        final File truffleAPI = new File(TruffleLanguage.class.getProtectionDomain().getCodeSource().getLocation().toURI());
-        final File sl = new File(SLLanguage.class.getProtectionDomain().getCodeSource().getLocation().toURI());
-        final File antlr4 = new File(org.antlr.v4.runtime.Parser.class.getProtectionDomain().getCodeSource().getLocation().toURI());
-        final File junit = new File(TestCase.class.getProtectionDomain().getCodeSource().getLocation().toURI());
-        assertTrue("SDK API exists: " + sdkAPI, sdkAPI.exists());
-        assertTrue("truffle-api JAR exists: " + truffleAPI, truffleAPI.exists());
-        assertTrue("sl JAR exists: " + sl, sl.exists());
-        assertTrue("antlr4 JAR exists: " + antlr4, antlr4.exists());
-        assertTrue("junit JAR exists: " + junit, junit.exists());
-
-        System.setProperty("graal-sdk.jar", sdkAPI.getAbsolutePath());
-        System.setProperty("truffle.jar", truffleAPI.getAbsolutePath());
-        System.setProperty("sl.jar", sl.getAbsolutePath());
-        System.setProperty("antlr4.jar", antlr4.getAbsolutePath());
-        System.setProperty("junit.jar", junit.getAbsolutePath());
-
-        return JPDASupport.createTestSuite(DebugSLTest.class);
-    }
-
-    public void testStepIntoMainSL() throws Exception {
-        doStepIntoSL(0, "main", 2);
-    }
-    
-    public void testStepIntoInvokeAs() throws Exception {
-        doStepIntoSL(1, "init", 7);
-    }
-    
-    public void testStepIntoDynamicInterface() throws Exception {
-        doStepIntoSL(2, "main", 2);
-    }
-    
-    private void doStepIntoSL(int bpNum, String methodName, int lineNo) throws Exception {
-        try {
-            JPDASupport.removeAllBreakpoints();
-            org.netbeans.api.debugger.jpda.Utils.BreakPositions bp = org.netbeans.api.debugger.jpda.Utils.getBreakPositions(
-                sourceRoot
-                + "org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java");
-            LineBreakpoint lb = bp.getLineBreakpoints().get(bpNum);
-            dm.addBreakpoint(lb);
-            support = JPDASupport.attach("org.netbeans.modules.debugger.jpda.truffle.testapps.SLApp",
-                new String[0],
-                new File[] {
-                    new File(System.getProperty("graal-sdk.jar")),
-                    new File(System.getProperty("truffle.jar")),
-                    new File(System.getProperty("antlr4.jar")),
-                    new File(System.getProperty("sl.jar")),
-                    new File(System.getProperty("junit.jar")),
-                }
-            );
-            support.waitState(JPDADebugger.STATE_STOPPED);
-            support.stepInto();
-            final JPDADebugger debugger = support.getDebugger();
-            CallStackFrame frame = debugger.getCurrentCallStackFrame();
-            assertNotNull(frame);
-            // Check that frame is in the Truffle access method
-            String haltedClass = TruffleAccess.BASIC_CLASS_NAME;
-            Field haltedMethodField = TruffleAccess.class.getDeclaredField("METHOD_EXEC_HALTED");
-            haltedMethodField.setAccessible(true);
-            String haltedMethod = (String) haltedMethodField.get(null);
-            /* Debug where it's stopped at:
-            System.err.println("Stopped in "+frame.getClassName()+"."+frame.getMethodName()+"()");
-            CallStackFrame[] callStack = frame.getThread().getCallStack();
-            for (CallStackFrame sf : callStack) {
-                System.err.println("  at "+sf.getClassName()+"."+sf.getMethodName()+"():"+sf.getLineNumber(null)+"  stratum: "+sf.getDefaultStratum());
-            }*/
-            assertEquals("Stopped in Truffle halted class", haltedClass, frame.getClassName());
-            assertEquals("Stopped in Truffle halted method", haltedMethod, frame.getMethodName());
-            assertEquals("Unexpected stratum", TruffleStrataProvider.TRUFFLE_STRATUM, frame.getDefaultStratum());
-            
-            CurrentPCInfo currentPCInfo = TruffleAccess.getCurrentPCInfo(frame.getThread());
-            assertNotNull("Missing CurrentPCInfo", currentPCInfo);
-            TruffleStackFrame topFrame = currentPCInfo.getTopFrame();
-            assertNotNull("No top frame", topFrame);
-            SourcePosition sourcePosition = topFrame.getSourcePosition();
-            assertEquals("Bad source", "Meaning of world.sl", sourcePosition.getSource().getName());
-            assertEquals("Bad line", lineNo, sourcePosition.getStartLine());
-            assertEquals("Bad method name", methodName, topFrame.getMethodName());
-            
-            support.doContinue();
-            support.waitState(JPDADebugger.STATE_DISCONNECTED);
-        } finally {
-            if (support != null) {
-                support.doFinish();
-            }
-        }
-    }
-
-    public void testBreakpointsInSL() throws Exception {
-        try {
-            JPDASupport.removeAllBreakpoints();
-            org.netbeans.api.debugger.jpda.Utils.BreakPositions bp = org.netbeans.api.debugger.jpda.Utils.getBreakPositions(
-                sourceRoot
-                + "org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl");
-            LineBreakpoint lb = bp.getLineBreakpoints().get(0);
-            // An ugly way to transform the Java breakpoint into Truffle breakpoint, used in SL.
-            FileObject fo = URLMapper.findFileObject(new URL(lb.getURL()));
-            dm.addBreakpoint(new TruffleLineBreakpoint(EditorLineHandlerFactory.getHandler(fo, lb.getLineNumber())));
-            support = JPDASupport.attach("org.netbeans.modules.debugger.jpda.truffle.testapps.SLAppFromFile",
-                new String[] {
-                    sourceRoot + "org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl"
-                },
-                new File[] {
-                    new File(System.getProperty("graal-sdk.jar")),
-                    new File(System.getProperty("truffle.jar")),
-                    new File(System.getProperty("antlr4.jar")),
-                    new File(System.getProperty("sl.jar")),
-                    new File(System.getProperty("junit.jar")),
-                }
-            );
-            support.waitState(JPDADebugger.STATE_STOPPED);
-            
-            final JPDADebugger debugger = support.getDebugger();
-            CallStackFrame frame = debugger.getCurrentCallStackFrame();
-            assertNotNull(frame);
-            // Check that frame is in the Truffle guest language
-            assertEquals("Unexpected stratum", TruffleStrataProvider.TRUFFLE_STRATUM, frame.getDefaultStratum());
-            
-            CurrentPCInfo currentPCInfo = TruffleAccess.getCurrentPCInfo(frame.getThread());
-            assertNotNull("Missing CurrentPCInfo", currentPCInfo);
-            TruffleStackFrame topFrame = currentPCInfo.getTopFrame();
-            assertNotNull("No top frame", topFrame);
-            SourcePosition sourcePosition = topFrame.getSourcePosition();
-            assertEquals("Bad source", "TestApp.sl", sourcePosition.getSource().getName());
-            assertEquals("Bad line", lb.getLineNumber(), sourcePosition.getStartLine());
-            assertEquals("Bad method name", "main", topFrame.getMethodName());
-            
-            support.doContinue();
-            support.waitState(JPDADebugger.STATE_DISCONNECTED);
-        } finally {
-            if (support != null) {
-                support.doFinish();
-            }
-        }
-    }
-
-}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/JPDATestCase.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/JPDATestCase.java
new file mode 100644
index 0000000..b22939a
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/JPDATestCase.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import java.util.logging.Level;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.JPDASupport;
+import org.netbeans.api.debugger.jpda.JPDAThread;
+import org.netbeans.junit.NbModuleSuite;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.debugger.jpda.truffle.access.CurrentPCInfo;
+import org.netbeans.modules.debugger.jpda.truffle.access.TruffleAccess;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.source.SourceBinaryTranslator;
+import org.netbeans.modules.debugger.jpda.truffle.source.SourcePosition;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+import org.netbeans.modules.debugger.jpda.truffle.vars.impl.TruffleScope;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Utilities;
+
+public abstract class JPDATestCase extends NbTestCase {
+
+    protected final File sourceRoot = new File(System.getProperty("test.dir.src"));
+
+    protected static Test createSuite(Class<? extends TestCase> clazz) {
+        return NbModuleSuite.createConfiguration(clazz).
+                gui(false).
+                failOnException(Level.INFO).
+                enableClasspathModules(false). 
+                clusters(".*").
+                suite();
+    }
+
+    public JPDATestCase(String name) {
+        super(name);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        JPDASupport.removeAllBreakpoints();
+        super.setUp();
+    }
+
+    protected String getBinariesPath(String sourcesPath) {
+        return Utilities.toFile(SourceBinaryTranslator.source2Binary(FileUtil.toFileObject(new File(sourcesPath)))).getAbsolutePath();
+    }
+
+    protected final File getScriptSourceFile(String scriptName) {
+        String scriptPath = "org/netbeans/modules/debugger/jpda/truffle/scripts/" + scriptName;
+        scriptPath = scriptPath.replace('/', File.separatorChar);
+        return new File(sourceRoot, scriptPath);
+    }
+
+    protected final File getJavaSourceFile(String javaFileName) {
+        String sourcePath = "org/netbeans/modules/debugger/jpda/truffle/testapps/" + javaFileName;
+        sourcePath = sourcePath.replace('/', File.separatorChar);
+        return new File(sourceRoot, sourcePath);
+    }
+
+    protected final void runScriptUnderJPDA(String launcher, String scriptPath, ThrowableConsumer<JPDASupport> supportConsumer) throws Exception {
+        // Translate script path from source dir to target dir:
+        scriptPath = getBinariesPath(scriptPath);
+        JPDASupport support = JPDASupport.attachScript(launcher, scriptPath);
+        run(support, supportConsumer, false);
+    }
+
+    protected final void runJavaUnderJPDA(String mainClass, ThrowableConsumer<JPDASupport> supportConsumer) throws Exception {
+        JPDASupport support = JPDASupport.attach(mainClass);
+        run(support, supportConsumer, false);
+    }
+
+    private void run(JPDASupport support, ThrowableConsumer<JPDASupport> supportConsumer, boolean resume) throws Exception {
+        try {
+            support.waitState(JPDADebugger.STATE_STOPPED);
+            if (resume) {
+                support.doContinue();
+                support.waitState(JPDADebugger.STATE_STOPPED);
+            }
+            supportConsumer.accept(support);
+            support.waitState(JPDADebugger.STATE_DISCONNECTED);
+        } catch (Throwable t) {
+            // Report any exception just in case the finally block does not finish cleanly
+            t.printStackTrace();
+            throw t;
+        } finally {
+            support.doFinish();
+        }
+    }
+
+    protected TruffleStackFrame checkStoppedAtScript(JPDAThread thread, String sourcePath, int line) {
+        CurrentPCInfo currentPCInfo = TruffleAccess.getCurrentPCInfo(thread);
+        assertNotNull("Missing CurrentPCInfo, suspended at " + thread.getClassName() + "." + thread.getMethodName(), currentPCInfo);
+        TruffleStackFrame topFrame = currentPCInfo.getTopFrame();
+        assertNotNull("No top frame", topFrame);
+        SourcePosition sourcePosition = topFrame.getSourcePosition();
+        if (sourcePath != null && new File(sourcePath).isAbsolute()) {
+            assertEquals("Bad source", getBinariesPath(sourcePath), sourcePosition.getSource().getPath());
+        }
+        assertEquals("Bad line", line, sourcePosition.getStartLine());
+        return topFrame;
+    }
+
+    protected static TruffleVariable findVariable(TruffleScope scope, String name) {
+        for (TruffleVariable var : scope.getVariables()) {
+            if (var.getName().equals(name)) {
+                return var;
+            }
+        }
+        return null;
+    }
+
+    @FunctionalInterface
+    protected interface ThrowableConsumer<T> {
+
+        void accept(T t) throws Exception;
+    }
+
+    @FunctionalInterface
+    protected interface ThrowableBiConsumer<T, U> {
+
+        void accept(T t, U u) throws Exception;
+    }
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/PolyglotTest.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/PolyglotTest.java
new file mode 100644
index 0000000..36e90b8
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/PolyglotTest.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle;
+
+import java.io.File;
+import junit.framework.Test;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import org.netbeans.api.debugger.ActionsManager;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.jpda.CallStackFrame;
+import org.netbeans.api.debugger.jpda.JPDADebugger;
+import org.netbeans.api.debugger.jpda.LineBreakpoint;
+import org.netbeans.modules.debugger.jpda.truffle.frames.TruffleStackFrame;
+import org.netbeans.modules.debugger.jpda.truffle.vars.TruffleVariable;
+
+public class PolyglotTest extends JPDATestCase {
+
+    private static final String ACTION_PAUSE_IN_GRAAL = "pauseInGraalScript";
+
+    public PolyglotTest(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return createSuite(PolyglotTest.class);
+    }
+
+    @Override // The app loads scripts from the compiled classes location always
+    protected String getBinariesPath(String sourcesPath) {
+        String classesDir = System.getProperty("test.dir.classes");
+        if (classesDir == null) {
+            return super.getBinariesPath(sourcesPath);
+        }
+        String base = sourceRoot.getAbsolutePath();
+        if (!sourcesPath.startsWith(base)) {
+            return sourcesPath;
+        }
+        String relPath = sourcesPath.substring(base.length());
+        while (relPath.startsWith(File.separator)) {
+            relPath = relPath.substring(File.separator.length());
+        }
+        return new File(classesDir, relPath).getAbsolutePath();
+    }
+
+    public void testWeatherApp() throws Exception {
+        DebuggerManager dm = DebuggerManager.getDebuggerManager();
+        String sourcePathJS = getScriptSourceFile("Weather.js").getAbsolutePath();
+        String sourcePathPython = getScriptSourceFile("Weather.py").getAbsolutePath();
+        String sourcePathR = "org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.r"; // relative path in R
+        LineBreakpoint lb = LineBreakpoint.create(getJavaSourceFile("PolyglotWeatherApp.java").toURI().toURL().toString(), 30);
+        dm.addBreakpoint(lb);
+        runJavaUnderJPDA("org.netbeans.modules.debugger.jpda.truffle.testapps.PolyglotWeatherApp", support -> {
+            final JPDADebugger debugger = support.getDebugger();
+            CallStackFrame frame = debugger.getCurrentCallStackFrame();
+            assertEquals(30, frame.getLineNumber(null));
+            dm.removeBreakpoint(lb);
+            ActionsManager actions = DebuggerManager.getDebuggerManager().getCurrentEngine().getActionsManager();
+            assertFalse("Pause in Graal Script not enabled initially", actions.isEnabled(ACTION_PAUSE_IN_GRAAL));
+            support.stepOver();
+            assertTrue("Pause in Graal Script enabled after Engine creation", actions.isEnabled(ACTION_PAUSE_IN_GRAAL));
+            support.stepOver();
+            frame = debugger.getCurrentCallStackFrame();
+            assertEquals(32, frame.getLineNumber(null));
+            support.stepOver();
+            frame = debugger.getCurrentCallStackFrame();
+            assertEquals(33, frame.getLineNumber(null));
+            actions.doAction(ACTION_PAUSE_IN_GRAAL);
+            support.doContinue();
+            support.waitState(JPDADebugger.STATE_STOPPED);
+
+            // We should be suspended in the JavaScript
+            TruffleStackFrame tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 124);
+            assertEquals("JavaScript", tframe.getLanguage().getName());
+            support.stepInto();
+            checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 23);
+            support.stepOver(); // loading Ruby
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 26);
+            TruffleVariable rubyWeather = findVariable(tframe.getScopes()[0], "Weather");
+            assertNotNull("Weather variable", rubyWeather);
+            assertEquals("Ruby", rubyWeather.getLanguage().getName());
+            assertEquals("Weather", rubyWeather.getValue());
+            support.stepOver();
+            support.stepOver();
+            //support.stepOver();
+            checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 32);
+            support.stepOver(); // loading R
+            checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 35);
+            support.stepOver();
+            support.stepOver();
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 40);
+            TruffleVariable createModel = findVariable(tframe.getScopes()[0], "createModel");
+            assertEquals("R", createModel.getLanguage().getName());
+            assertEquals("closure", createModel.getType());
+            support.stepOver(); // loading Python
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 58);
+            TruffleVariable purchase = findVariable(tframe.getScopes()[0], "Purchase");
+            assertEquals("Python", purchase.getLanguage().getName());
+            assertEquals("function", purchase.getType());
+            support.stepOver();
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 61);
+            TruffleVariable cities = findVariable(tframe.getScopes()[0], "cities");
+            assertEquals("Host", cities.getLanguage().getName());
+            support.stepOver();
+            support.stepOver();
+            support.stepInto();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 79);
+            assertEquals("updateModel", tframe.getMethodName());
+            support.stepOver();
+            support.stepOver();
+            support.stepOver();
+            support.stepOver();
+
+            // Calling into R:
+            support.stepInto();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathR, 27);
+            assertEquals("R", tframe.getLanguage().getName());
+            assertEquals("createModel", tframe.getMethodName());
+            TruffleVariable getName = findVariable(tframe.getScopes()[0], "getName");
+            assertEquals("JavaScript", getName.getLanguage().getName());
+            support.stepOver();
+            support.stepOver();
+            checkStoppedAtScript(debugger.getCurrentThread(), sourcePathR, 33);
+            support.stepOver();
+
+            // Back in JavaScript:
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 92);
+            assertEquals("JavaScript", tframe.getLanguage().getName());
+            support.stepOver();
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 97);
+            TruffleVariable model = findVariable(tframe.getScopes()[0], "model");
+            assertEquals("R", model.getLanguage().getName());
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 98);
+            TruffleVariable numCities = findVariable(tframe.getScopes()[0], "numCities");
+            assertEquals("number", numCities.getType());
+            assertEquals("5", numCities.getValue());
+            support.stepOver();
+            support.stepOver();
+            support.stepOver();
+            support.stepOver();
+
+            // Calling into Ruby:
+            support.stepInto();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), null, 22); // In an eval script
+            assertEquals("Ruby", tframe.getLanguage().getName());
+            support.stepOut();
+
+            // Back in JavaScript
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 103);
+            support.stepOver();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 106);
+
+            // Calling into Python:
+            support.stepInto();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), null, 4); // In an eval script
+            assertEquals("Python", tframe.getLanguage().getName());
+            support.stepOver();
+            support.stepInto();
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), null, 9); // In an eval script
+            assertEquals("fruits", tframe.getMethodName());
+            support.stepOut();
+            support.stepOut();
+
+            // Back in JavaScript
+            tframe = checkStoppedAtScript(debugger.getCurrentThread(), sourcePathJS, 106);
+            assertEquals("JavaScript", tframe.getLanguage().getName());
+
+            support.doContinue();
+        });
+    }
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.js
similarity index 70%
copy from java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.js
index 6d11006..aaae1fad 100644
--- a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.js
@@ -17,8 +17,33 @@
  * under the License.
  */
 
-function main() {
-    x = 42;
-    println(x); // LBREAKPOINT
-    return x;
-}
\ No newline at end of file
+statement = "First Statement";
+
+function fnc1() {
+  let a = 20;
+  let o = {};
+  o.ao = "AO";
+  let arr = [];
+  arr = [5, 4, 3, 2, 1]
+
+  return 30;
+}
+
+function fnc2(n) {
+
+  let n1 = n + 1;
+  let f2 = 0;
+  if (n1 <= 10) {
+    f2 = fnc2(n1) + 1;
+  }
+  return f2;
+}
+
+ga = 6;
+fnc1();
+
+for (let i of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {
+
+  fnc2(i);
+
+}
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.py
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.py
index adfab1c..188e6bd 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.py
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,35 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+class TestObject:
+  def addAO(self): self.ao = "AO"
+def fnc1():
+  a = 20
+  o = TestObject()
+  o.addAO()
+  arr = []
+  arr = [5, 4, 3, 2, 1]
+
+  return 30
+
+
+def fnc2(n):
+
+  n1 = n + 1
+  f2 = 0
+  if n1 <= 10:
+    f2 = fnc2(n1) + 1
+
+  return f2
+
+
+ga = 6
+fnc1()
+
+for i in range(1, 10):
+
+  fnc2(i)
+
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.r
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.r
index adfab1c..a09ae20 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.r
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,35 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+x <- "First statement"
+
+fnc1 <- function() {
+  a <- 20
+  o <- list()
+  o <- list(ao = "AO")
+  arr <- c()
+  arr <- c(5, 4, 3, 2, 1)
+
+  return(30)
+}
+
+fnc2 <- function(n) {
+
+  n1 <- n + 1
+  f2 <- 0
+  if (n1 <= 10) {
+    f2 <- fnc2(n1) + 1
+  }
+  return(f2)
+}
+
+ga <- 6
+y <- fnc1()
+
+for (i in 1:10) {
+
+  fnc2(i)
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
+}
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.ruby
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.ruby
index adfab1c..3f0ad24 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/DebuggerBase.ruby
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,35 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+statement = "First Statement"
+
+def fnc1()
+  a = 20
+  o = Object.new
+  o.instance_variable_set :@ao, "AO"
+  arr = []
+  arr = [5, 4, 3, 2, 1]
+
+  30
+end
+
+def fnc2(n)
+
+  n1 = n + 1
+  f2 = 0
+  if (n1 <= 10)
+    f2 = fnc2(n1) + 1
+  end
+  f2
+end
+
+$ga = 6
+fnc1()
+
+for i in 1..10 do
+
+  fnc2(i)
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
+end
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.js
similarity index 52%
rename from java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl
rename to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.js
index 6d11006..3390c66 100644
--- a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/TestApp.sl
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.js
@@ -17,8 +17,45 @@
  * under the License.
  */
 
-function main() {
-    x = 42;
-    println(x); // LBREAKPOINT
-    return x;
-}
\ No newline at end of file
+function typesTest() {
+  let a1 = [];
+  let a2 = [1, 2, [3, 4]];
+  let b1 = true;
+  let b2 = false;
+  let c1 = new TestClass();
+  let i1 = 0;
+  let i2 = 42;
+  let i3 = 42.42;
+  let i4 = -0.0;
+  let i5 = 1/i4;
+  let i6 = 1/0.0;
+  let i7 = -1/0.0;
+  let i8 = 0.0/0.0;
+  let aSparse = [1, 2];
+  aSparse[10] = 10;
+  let s1 = "String";
+  let f1 = function pow2(x) {
+    return x*x;
+  };
+  let d1 = new Date(1000000000);
+  let undef;
+  let nul = null;
+  let sy = Symbol('symbolic');
+  let o1 = {};
+  let o2 = new TestFncProp();
+  o2.fncProp = "Property";
+  o2.a = "A";
+  let map = new Map();
+  map.set("key1", 42);
+  map.set("key2", "v24");
+  debugger;
+  f1(5);
+}
+
+function TestFncProp() {
+}
+
+class TestClass {
+}
+
+typesTest();
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.py
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.py
index adfab1c..80aa271 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.py
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,27 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+import datetime
+def Callable():
+    pass
+
+
+def typesTest():
+
+    a = [1, 2, 3, 42]
+    b1 = True
+    b2 = False
+    i = 42
+    s = "string"
+    n = None
+    f = Callable
+    d = datetime.datetime.now()
+    map = dict()
+    map["key1"] = 42
+    map["key2"] = "v24"
+
+    bp = "breakpoint is here"
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
+typesTest()
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.r
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.r
index adfab1c..f84a7da 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.r
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,27 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+Callable <- function() {
+
+}
+
+typesTest <- function() {
+
+    a <- c(1, 2, 3, 42)
+    b1 <- TRUE
+    b2 <- FALSE
+    i <- 42
+    s <- "string"
+    n <- NULL
+    f <- Callable
+    d <- Sys.Date()
+    map <- new.env()
+    map[["key1"]] <- 42
+    map[["key2"]] <- "v24"
+
+    bp <- "breakpoint is here"
+}
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
+typesTest()
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.ruby
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.ruby
index adfab1c..f3c8cca 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Types.ruby
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,37 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+def Callable
+
+end
+
+def typesTest
+
+  a1 = []
+  a2 = [1, 2, [3, 4]]
+  b1 = true
+  b2 = false
+  null = nil
+  i1 = 0
+  i2 = 42
+  i3 = 42.42
+  i4 = -0.0;
+  i5 = 1/i4;
+  i6 = 1/0.0;
+  i7 = -1/0.0;
+  i8 = 0.0/0.0;
+  nc = 2 + 3i
+  nr = Rational(5.5)
+  f = method(:Callable)
+  d = Time.now
+  str = "A String"
+  symbol = :symbolic
+  hash = {:a => 1, "b" => 2}
+  i1 + i2
+
+end
+
+typesTest()
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.js b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.js
new file mode 100644
index 0000000..c2017aa
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.js
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+function weather() {
+
+  // Load the Ruby module
+  Polyglot.eval("application/x-ruby", "eval(File.open(\"org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.rb\").read)");
+
+  let Weather = Polyglot.import('weather')
+  Polyglot.export('tempInCity', function(name) {
+    return Weather.temperature_in_city(name);
+  });
+
+  // Load the R module
+  console.log("Preparing weather model... This may take a while.");
+  Polyglot.eval("application/x-r", "source(\"org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.r\")");
+
+  // Import the function exported from the R module
+  let createModel = Polyglot.import('createModel');
+  let predictTemp = Polyglot.import('do_predict');
+  let plotModel = Polyglot.import('plotModel');
+
+  // Load the Python module
+  Polyglot.eval("text/x-python", "import polyglot\n" +
+        "@polyglot.export_value\n" +
+        "def purchase(n):\n" +
+        "    bill = 0\n" +
+        "    bill += fruits(n, n // 2)\n" +
+        "    return bill\n" +
+        "\n" +
+        "def fruits(a, b):\n" +
+        "    prices = {'apple': 0.40, 'banana': 0.50}\n" +
+        "    my_purchase = {\n" +
+        "        'apple': a,\n" +
+        "        'banana': b}\n" +
+        "    grocery_bill = 0\n" +
+        "    for f in my_purchase:\n" +
+        "        grocery_bill += prices[f] * my_purchase[f]\n" +
+        "    return grocery_bill\n");
+  let Purchase = Polyglot.import('purchase')
+
+  let cityService = new (Java.type('org.netbeans.modules.debugger.jpda.truffle.testapps.WeatherCityService'));
+  var cities = cityService.getAll();
+
+  let javaNullObj = cityService.getNull();
+
+  // Create the linear regression model -> calls to R
+  let updateModel = function(size) {
+    function adjustIndex(i) {
+      if (i >= 1) {
+        return i - 1;
+      } else {
+        throw 'Wrong index: ' + i;
+      }
+    }
+    function convertTemp(conversion, t) {
+      switch(conversion) {
+        case 'C2F': return t * 1.8 + 32;
+        case 'F2C': return (t - 32) / 1.8;
+        default: throw "Unsupported conversion: " + conversion;
+      }
+    }
+    let getName = function(i) {
+      return cities[adjustIndex(i)].getName();
+    }
+    let getLatitude = function(i) {
+      return cities[adjustIndex(i)].getLatitude();
+    }
+    let getLongitude = function(i) {
+      return cities[adjustIndex(i)].getLongitude();
+    }
+    let getTemperature = function(i) {
+      let c = cities[adjustIndex(i)];
+      return convertTemp('C2F', c.getTemperature());
+    }
+    return createModel(size, cities.length, getName, getLatitude, getLongitude, getTemperature);
+  }
+
+  let model = updateModel(5);
+
+  let numCities = model.data.name.length;
+  print("Have " + numCities + " cities:");
+  for (let i = 0; i < numCities; i++) {
+    let name = cities[i].getName();
+
+    // Step into Ruby
+    let temperature = Weather.temperature_in_city(name);
+
+    // Step into Python
+    let purchase = Purchase(i);
+    print(" City " + name + ", " + cities[i].getCountry() + " has temperature " + temperature + "°C and bill $" + purchase);
+  }
+
+  print("Approximated temperatures by latitude are:");
+  let tMean = 0;
+  for (let lat = 90; lat >= -90; lat -= 10) {
+
+    // Step into R
+    let t = predictTemp(model, lat);
+    print("Temperature at latitude " + lat + " is " + t + "°C.");
+    tMean += t;
+  }
+  tMean /= 19;
+  return tMean;
+}
+
+// Step into the weather test
+weather();
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.py
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.py
index adfab1c..f590933 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.py
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,22 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+import polyglot
+@polyglot.export_value
+def purchase(n):
+    bill = 0
+    bill += fruits(n, n // 2)
+    return bill
+
+def fruits(a, b):
+    prices = {'apple': 0.40, 'banana': 0.50}
+    my_purchase = {
+        'apple': a,
+        'banana': b}
+    grocery_bill = 0
+    for f in my_purchase:
+        grocery_bill += prices[f] * my_purchase[f]
+    return grocery_bill
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.r b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.r
new file mode 100644
index 0000000..3df2d48
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.r
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Import the tempInCity function exported from the Ruby module
+tempInCity <- import('tempInCity')
+
+# The lattice library is needed for the visualization
+library(lattice)
+
+createModel <- function(size, length, getName, getLat, getLong, getTemp) {
+  idx <- sample(1:length, size)
+  data <- as.data.frame(list(
+      name = sapply(idx, function(i) getName(i)),
+      lat = sapply(idx, function(i) getLat(i)),
+      long = sapply(idx, function(i) getLong(i)),
+      temp = sapply(idx, function(i) getTemp(i))))
+  list(data=data, model=lm(temp~lat, data=data))
+}
+
+do_predict <- function(model, lat) {
+  predict(model$model, as.data.frame(list(lat = lat)))[[1]]
+}
+
+plotModel <- function(model) {
+  svg()
+  print(xyplot(temp ~ lat, data = model$data,
+    panel = function(x, y) {
+      panel.xyplot(x, y, cex=2, pch=19)
+      panel.abline(model$model)
+      labelsIdx <- seq(1, length(x), length.out = 10) # show only 10 labels, to make the graph more readable
+      panel.text(x[labelsIdx] + 1, y[labelsIdx], model$data$name[labelsIdx], adj = c(0, 0.5))
+  }));
+  grDevices:::svg.off()
+}
+
+# Export the functions
+export('createModel', createModel)
+export('do_predict', do_predict)
+export('plotModel', plotModel)
+
diff --git a/java/debugger.jpda.truffle/nbproject/project.properties b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.rb
similarity index 67%
copy from java/debugger.jpda.truffle/nbproject/project.properties
copy to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.rb
index adfab1c..aaea358 100644
--- a/java/debugger.jpda.truffle/nbproject/project.properties
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.rb
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,13 +15,15 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+
+module Weather
+  def self.temperature_in_city(name)
+    name = Truffle::Interop.from_java_string(name)
+    cityArray = name.bytes
+    citySum = cityArray.reduce(0, :+)
+    weatherTemperature = citySum.modulo(36)
+  end
+end
 
-javac.compilerargs=-Xlint:unchecked
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-nbm.module.author=Martin Entlicher
-requires.nb.javac=true
-truffle.sl=external/antlr4-runtime-4.7.2.jar:external/truffle-sl-1.0.0-rc6.jar
-cp.extra=${tools.jar}:${truffle.sl}
-test-unit-sys-prop.test.dir.src=${basedir}/test/unit/src/
-test-unit-sys-prop.netbeans.user=${basedir}/work/nb_user_dir
+Truffle::Interop.export :weather, Weather
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLAppFromFile.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/PolyglotWeatherApp.java
similarity index 62%
rename from java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLAppFromFile.java
rename to java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/PolyglotWeatherApp.java
index e50a3f6..1517d1a 100644
--- a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLAppFromFile.java
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/PolyglotWeatherApp.java
@@ -16,28 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.netbeans.modules.debugger.jpda.truffle.testapps;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-
+import java.io.IOException;
 import org.graalvm.polyglot.Context;
 import org.graalvm.polyglot.Source;
 import org.graalvm.polyglot.Value;
-import static org.junit.Assert.assertEquals;
 
-public class SLAppFromFile {
-    public static void main(String... args) throws Exception {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        Context context = Context.newBuilder().out(os).build();
+public class PolyglotWeatherApp {
 
-        String path = args[0];
-        Source src = Source.newBuilder("sl", new File(path)).build();
-        
-        Value result = context.eval(src); // LBREAKPOINT
-
-        assertEquals("Expected result", 42L, result.asLong());
-        assertEquals("Expected output", "42\n", os.toString("UTF-8"));
+    public static void main(String[] args) throws IOException {
+        Context context = Context.newBuilder().allowAllAccess(true).build();
+        File script = new File(new File("").getAbsolutePath(), "org/netbeans/modules/debugger/jpda/truffle/scripts/Weather.js");
+        Source source = Source.newBuilder("js", script).build();
+        Value result = context.eval(source);
+        double t = result.asDouble();
+        System.out.println("Mean temperature = "+t);
     }
+
 }
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
deleted file mode 100644
index 4d1e9f6..0000000
--- a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/SLApp.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.netbeans.modules.debugger.jpda.truffle.testapps;
-
-import java.io.ByteArrayOutputStream;
-
-import org.graalvm.polyglot.Context;
-import org.graalvm.polyglot.Source;
-import org.graalvm.polyglot.Value;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-public class SLApp {
-    public static void main(String... args) throws Exception {
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-
-        Source src = Source.newBuilder("sl",
-            "function main() {\n" +
-            "  x = 42;\n" +
-            "  println(x);\n" +
-            "  return x;\n" +
-            "}\n"+
-            "function init() {\n"+
-            "  obj = new();\n"+
-            "  obj.fourtyTwo = main;\n"+
-            "  return obj;\n"+
-            "}\n",
-            "Meaning of world.sl").build();
-        
-        Context context = Context.newBuilder().allowAllAccess(true).out(os).build();
-        Value result = context.eval(src);                           // LBREAKPOINT
-
-        assertEquals("Expected result", 42L, result.asLong());
-        assertEquals("Expected output", "42\n", os.toString("UTF-8"));
-        
-        // dynamic generated interface
-        Value init = context.getBindings("sl").getMember("init");
-        assertNotNull("init method found", init);
-        Compute c = init.execute().as(Compute.class);                           // LBREAKPOINT
-        Object result42 = c.fourtyTwo();                                        // LBREAKPOINT
-        assertEquals("Expected result", 42L, result42);
-        assertEquals("Expected output", "42\n42\n", os.toString("UTF-8"));
-    }
-    
-    public static interface Compute {
-        public Number fourtyTwo();
-    }
-}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCity.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCity.java
new file mode 100644
index 0000000..3f20183
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCity.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle.testapps;
+
+public class WeatherCity {
+
+    private final int id;
+    private final String name;
+    private final String country;
+    private final int population;
+    private final double longitude;
+    private final double lat;
+    private double temperature;
+
+    public WeatherCity(int id, String name, String country, int population, double lat, double longitude, double temperature) {
+        this.id = id;
+        this.name = name;
+        this.country = country;
+        this.longitude = longitude;
+        this.lat = lat;
+        this.temperature = temperature;
+        this.population = population;
+    }
+
+    public int getId() { return id; }
+    public String getName() { return name; }
+    public String getCountry() { return country; }
+    public int getPopulation() { return population; }
+    public double getLatitude() { return lat; }
+    public double getLongitude() { return longitude; }
+    public double getTemperature() { return temperature; }
+
+    public void updateTemperature(double newValue) {
+        temperature = newValue;
+    }
+}
diff --git a/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCityService.java b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCityService.java
new file mode 100644
index 0000000..048279e
--- /dev/null
+++ b/java/debugger.jpda.truffle/test/unit/src/org/netbeans/modules/debugger/jpda/truffle/testapps/WeatherCityService.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.debugger.jpda.truffle.testapps;
+
+import java.util.Arrays;
+
+public class WeatherCityService {
+
+    // A test sample
+    private static WeatherCity[] cities = new WeatherCity[] {
+        new WeatherCity(0, "San Roque", "N. Mariana Islands", 1097, 15.25, 145.77, 13.2346746509429),
+        new WeatherCity(1, "La Sabana", "Honduras", 1572, 15.37, -87.93, 29.5364631644916),
+        new WeatherCity(2, "Videbaek", "Denmark", 4076, 56.08, 8.63, 24.2545498488471),
+        new WeatherCity(3, "Nasirabad", "Pakistan", 28506, 27.38, 67.91, 25.4554680001456),
+        new WeatherCity(4, "Okazaki", "Japan", 355573, 34.96, 137.16, 7.89123377134092),
+        new WeatherCity(5, "Huddersfield", "UK", 149607, 53.66, -1.8, 26.9585336048622),
+        new WeatherCity(6, "Cocentaina", "Spain", 11223, 38.75, -0.44, 16.3208602035884),
+        new WeatherCity(7, "Ankathia", "Greece", 1300, 40.56, 22.47, 9.76689549605362),
+        new WeatherCity(8, "Mediesu Aurit", "Romania", 7062, 47.78, 23.15, 10.8357614693232),
+        new WeatherCity(9, "Juan Lopez", "Dominican Republic", 1547, 19.43, -70.52, 14.5722625446506),
+        new WeatherCity(10, "Birnin Kebbi", "Nigeria", 111883, 12.46, 4.19, 23.3168364593294),
+        new WeatherCity(11, "Chistopol", "Russia", 62020, 55.36, 50.64, 3.51541253109463),
+        new WeatherCity(12, "Periyialion", "Greece", 2120, 37.95, 22.84, 16.3009215018246),
+        new WeatherCity(13, "Togo", "Japan", 42643, 35.1, 137.04, 8.89008317119442),
+        new WeatherCity(14, "Shiyan", "China", 413581, 32.57, 110.78, 20.1505158017389),
+        new WeatherCity(15, "Iira", "Estonia", 138, 58.99, 24.72, 12.9968547783792),
+        new WeatherCity(16, "Ilha Soltera", "Brazil", 25305, -20.38, -51.34, 14.7320180023089),
+        new WeatherCity(17, "Ikorodu", "Nigeria", 321809, 6.61, 3.51, 22.5338149268646),
+        new WeatherCity(18, "Kocani", "Macedonia", 34448, 41.93, 22.4, 2.02855428215116),
+        new WeatherCity(19, "Siatista", "Greece", 5603, 40.26, 21.54, 22.2741849503946),
+        new WeatherCity(20, "Pella", "Greece", 2482, 40.76, 22.52, 13.1903853449039),
+    };
+
+    public int getTotalCount() { return cities.length; }
+    public WeatherCity[] getAll() { return cities; }
+    public WeatherCity[] getAllPaged(int skip, int pageSize) {
+        return Arrays.stream(cities).skip(skip).limit(pageSize).toArray(n -> new WeatherCity[n]);
+    }
+
+    public WeatherCity findByName(String name) {
+        return Arrays.stream(cities).filter(x -> x.getName().equals(name)).findFirst().orElse(null);
+    }
+
+    public void updateTemperature(int id, double temperature) {
+        cities[id].updateTemperature(temperature);
+    }
+    public Object getNull() {
+        return null;
+    }
+
+}
diff --git a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
index 8fbdfa9..5a7d973 100644
--- a/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
+++ b/java/debugger.jpda.truffle/truffle-backend/org/netbeans/modules/debugger/jpda/backend/truffle/JPDATruffleAccessor.java
@@ -501,6 +501,7 @@ public class JPDATruffleAccessor extends Object {
             bb.resolveListener(new Breakpoint.ResolveListener() {
                 @Override
                 public void breakpointResolved(Breakpoint breakpoint, SourceSection section) {
+                    trace("JPDATruffleAccessor breakpointResolved({0}, {1})", breakpoint, section);
                     // Notify breakpoint resolution after we actually install it.
                     // Resolution that is performed synchronously with the breakpoint installation
                     // would block doSetLineBreakpoint() method invocation on breakpointResolvedAccess breakpoint
diff --git a/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/JPDASupport.java b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/JPDASupport.java
index b13a30a..31eedce 100644
--- a/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/JPDASupport.java
+++ b/java/debugger.jpda/test/unit/src/org/netbeans/api/debugger/jpda/JPDASupport.java
@@ -19,67 +19,70 @@
 
 package org.netbeans.api.debugger.jpda;
 
+import com.sun.jdi.Bootstrap;
+import com.sun.jdi.VirtualMachineManager;
+import com.sun.jdi.connect.AttachingConnector;
+import com.sun.jdi.connect.Transport;
+
+import java.beans.PropertyChangeEvent;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
-import org.netbeans.api.debugger.*;
-
-import java.io.*;
-import java.util.*;
-import java.net.URLClassLoader;
-import java.net.URL;
-import java.beans.PropertyChangeEvent;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
-import com.sun.jdi.connect.*;
-import com.sun.jdi.VirtualMachineManager;
-import com.sun.jdi.Bootstrap;
-//import org.netbeans.api.java.classpath.ClassPath;
 import junit.framework.Test;
 import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+
+import org.netbeans.api.debugger.ActionsManager;
+import org.netbeans.api.debugger.ActionsManagerListener;
+import org.netbeans.api.debugger.Breakpoint;
+import org.netbeans.api.debugger.DebuggerEngine;
+import org.netbeans.api.debugger.DebuggerManager;
+import org.netbeans.api.debugger.DebuggerManagerListener;
+import org.netbeans.api.debugger.Session;
+import org.netbeans.api.debugger.Watch;
 import org.netbeans.api.java.classpath.ClassPath;
-//import org.netbeans.spi.java.classpath.support.ClassPathSupport;
-import org.netbeans.api.java.queries.SourceForBinaryQuery;
 import org.netbeans.junit.NbModuleSuite;
 import org.netbeans.junit.NbModuleSuite.Configuration;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
-import org.openide.util.Exceptions;
 
 /**
  * Contains support functionality for unit tests.
  *
  * @author Maros Sandor
  */
-public class JPDASupport implements DebuggerManagerListener {
+public final class JPDASupport implements DebuggerManagerListener {
 
     private static final boolean    verbose = false;
-    private static final DateFormat df = new SimpleDateFormat("kk:mm:ss.SSS");
     private static DebuggerManager  dm = DebuggerManager.getDebuggerManager ();
 
     private JPDADebugger            jpdaDebugger;
     private DebuggerEngine          debuggerEngine;
+    private final ProcessIO         processIO;
     
-
-    private Object [] debuggerStartLock = new Object[1];
-    private Object [] stepLock = new Object[1];
-
-    private Object              STATE_LOCK = new Object ();
-    
+    private Object                  STATE_LOCK = new Object ();
     
-    private JPDASupport (JPDADebugger jpdaDebugger) {
+    private JPDASupport (JPDADebugger jpdaDebugger, ProcessIO pio) {
         this.jpdaDebugger = jpdaDebugger;
         jpdaDebugger.addPropertyChangeListener (this);
         DebuggerEngine[] de = dm.getDebuggerEngines ();
         int i, k = de.length;
-        for (i = 0; i < k; i++)
+        for (i = 0; i < k; i++) {
             if (de [i].lookupFirst (null, JPDADebugger.class) == jpdaDebugger) {
                 debuggerEngine = de [i];
                 break;
             }
+        }
+        this.processIO = pio;
     }
     
     public static Test createTestSuite(Class<? extends TestCase> clazz) {
@@ -182,26 +185,62 @@ public class JPDASupport implements DebuggerManagerListener {
                 break;
             }
         }
-        if (connector == null) 
-            throw new RuntimeException
-                ("No attaching socket connector available");
-
+        if (connector == null) {
+            throw new RuntimeException("No attaching socket connector available");
+        }
         JPDADebugger jpdaDebugger = JPDADebugger.attach (
             "localhost", 
             port, 
             createServices ()
         );
-        return new JPDASupport (jpdaDebugger);
+        return new JPDASupport (jpdaDebugger, pio);
     }
 
-    
+    public static JPDASupport attachScript(String launcher, String path) throws IOException, DebuggerStartException {
+        String [] cmdArray = new String [] {
+            System.getProperty ("java.home") + File.separatorChar +
+                "bin" + File.separatorChar + launcher,
+            "--jvm",
+            "--vm.agentlib:jdwp=transport=dt_socket,suspend=y,server=y",
+            path
+        };
+        Process process = Runtime.getRuntime ().exec (cmdArray);
+        String line = readLine (process.getInputStream ());
+        int port = Integer.parseInt (line.substring (line.lastIndexOf (':') + 1).trim ());
+        ProcessIO pio = new ProcessIO (process);
+        pio.go();
+
+        VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
+        List aconnectors = vmm.attachingConnectors();
+        AttachingConnector connector = null;
+        for (Iterator i = aconnectors.iterator(); i.hasNext();) {
+            AttachingConnector ac = (AttachingConnector) i.next();
+            Transport t = ac.transport ();
+            if (t != null && t.name().equals("dt_socket")) {
+                connector = ac;
+                break;
+            }
+        }
+        if (connector == null) {
+            throw new RuntimeException("No attaching socket connector available");
+        }
+
+        JPDADebugger jpdaDebugger = JPDADebugger.attach (
+            "localhost",
+            port,
+            new Object[]{}
+        );
+        return new JPDASupport(jpdaDebugger, pio);
+    }
+
+
     // public interface ........................................................
     
     public void doContinue () {
-        if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) 
+        if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) {
             throw new IllegalStateException ();
-        debuggerEngine.getActionsManager ().doAction 
-            (ActionsManager.ACTION_CONTINUE);
+        }
+        debuggerEngine.getActionsManager().doAction(ActionsManager.ACTION_CONTINUE);
     }
 
     public void stepOver () {
@@ -217,9 +256,10 @@ public class JPDASupport implements DebuggerManagerListener {
     }
 
     public void step (Object action) {
-        if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED)
+        if (jpdaDebugger.getState () != JPDADebugger.STATE_STOPPED) {
             throw new IllegalStateException ();
-        debuggerEngine.getActionsManager ().doAction (action);
+        }
+        DebuggerManager.getDebuggerManager().getCurrentEngine().getActionsManager().doAction(action);
         waitState (JPDADebugger.STATE_STOPPED);
     }
 
@@ -245,6 +285,11 @@ public class JPDASupport implements DebuggerManagerListener {
         debuggerEngine.getActionsManager ().
             doAction (ActionsManager.ACTION_KILL);
         waitState (JPDADebugger.STATE_DISCONNECTED);
+        try {
+            processIO.join();
+        } catch (InterruptedException ex) {
+            // Interrupted
+        }
     }
 
     public void waitState (int state) {
@@ -322,7 +367,7 @@ public class JPDASupport implements DebuggerManagerListener {
     }
 
     private static String readLine (InputStream in) throws IOException {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         for (;;) {
             int c = in.read();
             if (c == -1) throw new EOFException();
@@ -363,7 +408,12 @@ public class JPDASupport implements DebuggerManagerListener {
             cmdArray = arr;
         }
 
-        return Runtime.getRuntime ().exec (cmdArray);
+        ProcessBuilder pb = new ProcessBuilder().command(cmdArray);
+        String classesDir = System.getProperty("test.dir.classes");
+        if (classesDir != null) {
+            pb.directory(new File(classesDir));
+        }
+        return pb.start();
     }
     
     private static String getClassPath(File[] extraCP) {
@@ -477,7 +527,9 @@ public class JPDASupport implements DebuggerManagerListener {
     
     private static class ProcessIO {
 
-        private Process p;
+        private final Process p;
+        private Thread threadOut;
+        private Thread threadErr;
 
         public ProcessIO(Process p) {
             this.p = p;
@@ -487,8 +539,14 @@ public class JPDASupport implements DebuggerManagerListener {
             InputStream out = p.getInputStream();
             InputStream err = p.getErrorStream();
 
-            new SimplePipe(System.out, out).start();
-            new SimplePipe(System.out, err).start();
+            (threadOut = new SimplePipe(System.out, out)).start();
+            (threadErr = new SimplePipe(System.out, err)).start();
+        }
+
+        private void join() throws InterruptedException {
+            threadOut.join();
+            threadErr.join();
+            assertEquals(0, p.waitFor());
         }
     }
 
diff --git a/nbbuild/travis/scripting.sh b/nbbuild/travis/scripting.sh
index 82e47ba..1c7a06e 100755
--- a/nbbuild/travis/scripting.sh
+++ b/nbbuild/travis/scripting.sh
@@ -35,6 +35,7 @@ fi
 
 $GRAALVM/bin/gu install python
 $GRAALVM/bin/gu install R
+$GRAALVM/bin/gu install ruby
 
 # Test on GraalVM
 
@@ -45,3 +46,4 @@ JAVA_HOME=$GRAALVM ant -f platform/core.network/build.xml test
 JAVA_HOME=$GRAALVM ant -f webcommon/libs.graaljs/build.xml test
 JAVA_HOME=$GRAALVM ant -f profiler/profiler.oql/build.xml test
 JAVA_HOME=$GRAALVM ant -f java/nashorn.execution/build.xml test
+JAVA_HOME=$GRAALVM ant -f java/debugger.jpda.truffle/build.xml test

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists