Class DebuggerTester

java.lang.Object
com.oracle.truffle.tck.DebuggerTester
All Implemented Interfaces:
AutoCloseable

public final class DebuggerTester extends Object implements AutoCloseable
Test utility class that makes it easier to test and debug debugger functionality for guest languages. Testing suspended callbacks can be cumbersome when having to assert multiple sequential events. The debugger tester allows to test suspended callbacks using sequential code that allows to assert multiple events. It does so by running the engine on a separate thread and it uses internal APIs to allow access to the SuspendedEvent from another Thread. Do not use this class for anything else than testing.

The debugger tester can print debug traces to standard output with -Dtruffle.debug.trace=true. Example usage:

public void testDebugging() {
    try (DebuggerTester tester = new DebuggerTester()) {
        // use your guest language source here
        Source source = null;
        try (DebuggerSession session = tester.startSession()) {
            session.suspendNextExecution();
            tester.startEval(source);

            tester.expectSuspended(new SuspendedCallback() {
                @Override
                public void onSuspend(SuspendedEvent event) {
                    // assert suspended event is proper here
                    event.prepareStepInto(1);

                }
            });
            tester.expectSuspended(new SuspendedCallback() {
                @Override
                public void onSuspend(SuspendedEvent event) {
                    // assert another suspended event is proper here
                    event.prepareContinue();
                }
            });

            // expect no more suspended events
            tester.expectDone();
        }
    }
}
Since:
0.16
  • Constructor Details

    • DebuggerTester

      public DebuggerTester()
      Constructs a new debugger tester instance. Boots up a new context on Thread in the background. The tester instance needs to be closed after use. Throws an AssertionError if the engine initialization fails.
      Since:
      0.16
    • DebuggerTester

      public DebuggerTester(org.graalvm.polyglot.Context.Builder contextBuilder)
      Constructs a new debugger tester instance with a pre-set context builder.
      Parameters:
      contextBuilder - a pre-set context builder. Only out and err streams are set on this builder prior the Context instance creation.
      Since:
      0.31
      See Also:
  • Method Details

    • getErr

      public String getErr()
      Returns the error output of the underlying context.
      Since:
      0.16
    • getOut

      public String getOut()
      Returns the standard output of the underlying context.
      Since:
      0.16
    • getDebugger

      public com.oracle.truffle.api.debug.Debugger getDebugger()
      Get the Debugger instance associated with the current engine.
      Since:
      0.27
    • startSession

      public com.oracle.truffle.api.debug.DebuggerSession startSession()
      Starts a new debugger session in the context's engine. The debugger session allows to suspend the execution and to install breakpoints. If multiple sessions are created for one evaluation then all suspended events are delegated to this debugger tester instance.
      Returns:
      a new debugger session
      Since:
      0.16
    • startSession

      public com.oracle.truffle.api.debug.DebuggerSession startSession(com.oracle.truffle.api.debug.SourceElement... sourceElements)
      Starts a new debugger session in the context's engine. The debugger session allows to suspend the execution on the provided source elements and to install breakpoints. If multiple sessions are created for one evaluation then all suspended events are delegated to this debugger tester instance.
      Parameters:
      sourceElements - a list of source elements
      Returns:
      a new debugger session
      Since:
      0.33
    • startEval

      public void startEval(org.graalvm.polyglot.Source s)
      Starts a new evaluation on the background thread. Only one evaluation can be active at a time. Please ensure that expectDone() completed successfully before starting a new evaluation. When no source is available please refer to startExecute(Function). Throws an IllegalStateException if another evaluation is still executing or the tester is already closed.
      Since:
      0.27
    • startExecute

      public void startExecute(Function<org.graalvm.polyglot.Context,org.graalvm.polyglot.Value> script)
      Starts a new script evaluation on the background thread. Only one evaluation can be active at a time. Please ensure that expectDone() completed successfully before starting a new evaluation. If a Source is available please refer to startEval(Source) . Throws an IllegalStateException if another evaluation is still executing or the tester is already closed.
      Since:
      20.0
    • expectSuspended

      public void expectSuspended(com.oracle.truffle.api.debug.SuspendedCallback callback)
      Expects a suspended event and returns it for potential assertions. If the execution completed or was killed instead then an assertion error is thrown. The returned suspended event is only valid until on of expectKilled(), expectSuspended(SuspendedCallback) or expectDone() is called again. Throws an IllegalStateException if the tester is already closed.
      Parameters:
      callback - handler to be called when the execution is suspended
      Since:
      0.16
    • expectSuspended

      public void expectSuspended(com.oracle.truffle.api.debug.SuspendedCallback callback, Function<String,Boolean> errorVerifier)
      Expects a suspended event and returns it for potential assertions, allows to verify errors printed to the error output.
      Parameters:
      callback - handler to be called when the execution is suspended
      errorVerifier - handler, which returns true when the error is expected
      Since:
      24.1
    • expectThrowable

      public Throwable expectThrowable()
      Expects the current evaluation to be completed with an error and not be killed or to produce further suspended events. It returns a string representation of the result value to be asserted. If the evaluation caused any errors they are thrown as AssertionError. Throws an IllegalStateException if the tester is already closed.
      Since:
      0.16
    • expectDone

      public String expectDone()
      Expects the current evaluation to be completed successfully and not be killed or to produce further suspended events. It returns a string representation of the result value to be asserted. If the evaluation caused any errors they are thrown as AssertionError. Throws an IllegalStateException if the tester is already closed.
      Since:
      0.16
    • expectKilled

      public void expectKilled()
      Expects the current evaluation to be killed and not be completed or to produce further suspended events. Throws an IllegalStateException if the tester is already closed. If the evaluation caused any errors besides the kill exception then they are thrown as AssertionError.
      Since:
      0.16
    • getEvalThread

      public Thread getEvalThread()
      Returns the thread that the execution started with startEval(Source) is running on.
      Returns:
      the thread instance
      Since:
      0.16
    • closeEngine

      public void closeEngine()
      Close the engine. It's not possible to evaluate code after engine is closed, use it when the engine needs to be closed before the debugger session.
      Since:
      0.30
    • close

      public void close()
      Closes the current debugger tester session and all its associated resources like the background thread. The debugger tester becomes unusable after closing.
      Specified by:
      close in interface AutoCloseable
      Since:
      0.16
    • assertLineBreakpointsResolution

      public void assertLineBreakpointsResolution(String sourceWithMarks, String resolvedMarkName, String language)
      Utility method that checks proper resolution of line breakpoints. Breakpoints are submitted to every line of the source and their resolution location is checked.

      The source need to contain resolution marks in the form of "R<line number>_" where <line number> is line number of the original breakpoint position and R is the resolved mark name. These marks need to be placed at the proper breakpoint resolution line/column position, for a breakpoint submitted to every line. When several submitted breakpoints resolve to the same position, an interval can be specified in the form of "R<line start number>-<line end number>_", where both start and end line numbers are inclusive. The marks are stripped off before execution.

      The guest language code with marks may look like:

       // test
       function test(n) {
         if (R1-3_n <= 1) {
           return R4_2 * n;
         }
         return R5-7_n - 1;
       }
       
      Parameters:
      sourceWithMarks - a source text, which contains the resolution marks
      resolvedMarkName - the mark name. It is used in a regular expression, therefore the mark must not have a special meaning in a regular expression.
      language - the source language
      Since:
      0.33
    • assertLineBreakpointsResolution

      public void assertLineBreakpointsResolution(String sourceWithMarks, DebuggerTester.PositionPredicate positionPredicate, String resolvedMarkName, String language)
      Parameters:
      positionPredicate - null to test line breakpoints on all lines, or a predicate that limits the testable lines.
      Since:
      19.3.0
      See Also:
    • assertColumnBreakpointsResolution

      public void assertColumnBreakpointsResolution(String sourceWithMarks, String breakpointMarkName, String resolvedMarkName, String language)
      Utility method that checks proper resolution of column breakpoints. Breakpoints are submitted to marked positions and their resolution location is checked.

      The source need to contain both breakpoint submission marks in the form of "B<number>_" and breakpoint resolution marks in the form of "R<number>_" where <number> is an identification of the breakpoint. These marks need to be placed at the proper breakpoint submission/resolution line/column position. When several submitted breakpoints resolve to the same position, an interval can be specified in the form of "R<start number>-<end number>_", where both start and end line numbers are inclusive. The marks are stripped off before execution.

      The guest language code with marks may look like:

       // B1_test
       function B2_test(n) {B3_
         if (R1-4_n <= B4_1) {B5_
           return R5_2 * n;
         }
         return R6_n - 1;
       B6_}
       
      Parameters:
      sourceWithMarks - a source text, which contains the resolution marks
      breakpointMarkName - the breakpoint submission mark name. It is used in a regular expression, therefore the mark must not have a special meaning in a regular expression.
      resolvedMarkName - the resolved mark name. It is used in a regular expression, therefore the mark must not have a special meaning in a regular expression.
      language - the source language
      Since:
      0.33
    • assertColumnBreakpointsResolution

      public void assertColumnBreakpointsResolution(String sourceWithMarks, String breakpointMarkName, String resolvedMarkName, String language, URI bpURI)
    • assertBreakpointsBreakEverywhere

      public void assertBreakpointsBreakEverywhere(org.graalvm.polyglot.Source source)
      Utility method that tests if a breakpoint submitted to any location in the source code suspends the execution. A two-pass test is performed. In the first pass, line breakpoints are submitted to every line. In the second pass, breakpoints are submitted to every line and column combination, even outside the source scope. It is expected that the breakpoints resolve to a nearest suspendable location and it is checked that all breakpoints are hit.
      Parameters:
      source - a source to evaluate with breakpoints submitted everywhere
      Since:
      0.33
    • assertBreakpointsBreakEverywhere

      public void assertBreakpointsBreakEverywhere(org.graalvm.polyglot.Source source, DebuggerTester.PositionPredicate positionPredicate)
      Utility method that tests if a breakpoint submitted to any location permitted by the DebuggerTester.PositionPredicate in the source code suspends the execution. A two-pass test is performed. In the first pass, line breakpoints are submitted to every testable line. In the second pass, breakpoints are submitted to every testable line and column combination, even outside the source scope, if permitted by the DebuggerTester.PositionPredicate. It is expected that the breakpoints resolve to a nearest suspendable location and it is checked that all submitted breakpoints are hit.
      Parameters:
      source - a source to evaluate with breakpoints submitted everywhere
      positionPredicate - null to submit breakpoints everywhere, or a predicate that limits the testable positions.
      Since:
      19.3.0
    • getSourceImpl

      public static com.oracle.truffle.api.source.Source getSourceImpl(org.graalvm.polyglot.Source source)
      Get Truffle Source that corresponds to the Polyglot Source. This is a bridge between the two Source implementations.
      Since:
      0.28