From 6779fa743fa3df82ed7a0f3c964f79ed0fd0bef7 Mon Sep 17 00:00:00 2001 From: Tim Voronov Date: Wed, 16 Sep 2026 09:40:41 -0400 Subject: [PATCH] feat: add context support to debugger session operations --- go.mod | 4 +- go.sum | 8 +- pkg/debugger/fake_line_reader_test.go | 23 ++++ pkg/debugger/fake_session_test.go | 141 ++++++++++++++++++++ pkg/debugger/prompt.go | 20 +-- pkg/debugger/prompt_test.go | 178 +++++++------------------- pkg/debugger/session.go | 15 ++- pkg/runtime/debug_context_test.go | 86 +++++++++++++ pkg/runtime/debug_test.go | 3 + 9 files changed, 325 insertions(+), 153 deletions(-) create mode 100644 pkg/debugger/fake_line_reader_test.go create mode 100644 pkg/debugger/fake_session_test.go create mode 100644 pkg/runtime/debug_context_test.go diff --git a/go.mod b/go.mod index 4ea63b9..c639d76 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/MontFerret/contrib/modules/web/sitemap v1.0.0-rc.16 github.com/MontFerret/contrib/modules/xml v1.0.0-rc.16 github.com/MontFerret/contrib/modules/yaml v1.0.0-rc.16 - github.com/MontFerret/ferret/v2 v2.0.0-alpha.54 + github.com/MontFerret/ferret/v2 v2.0.0-alpha.55 github.com/MontFerret/specs v1.12.0 github.com/antlr4-go/antlr/v4 v4.13.1 github.com/chzyer/readline v1.5.1 @@ -46,7 +46,7 @@ require ( github.com/BurntSushi/toml v1.6.0 // indirect github.com/JohannesKaufmann/dom v0.3.1 // indirect github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2 // indirect - github.com/MontFerret/api v1.0.0-alpha.16 // indirect + github.com/MontFerret/api v1.0.0-alpha.19 // indirect github.com/MontFerret/contrib/pkg/common v0.2.0 // indirect github.com/MontFerret/cssx v0.2.0 // indirect github.com/PuerkitoBio/goquery v1.13.0 // indirect diff --git a/go.sum b/go.sum index 5b976c5..1bac4dc 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2 h1:XFJZFWESIWlUEHHjzBuv8R github.com/JohannesKaufmann/html-to-markdown/v2 v2.5.2/go.mod h1:BHWO8lJzttJLqwuV8Rb1B3OG2OSzLbssZDI1FRg2eAA= github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/MontFerret/api v1.0.0-alpha.16 h1:OhAyPzy3s57BHiI0mHn4HLv456985nmWCtQgSdUESXg= -github.com/MontFerret/api v1.0.0-alpha.16/go.mod h1:wz5bfUIGYkED8Hqz9CdsW0o2jSgagotbVLOCbHHacSI= +github.com/MontFerret/api v1.0.0-alpha.19 h1:zRAb2rAMFxhKggmVTEEQfWxfaSz6+p5D6b+C5P/RXZw= +github.com/MontFerret/api v1.0.0-alpha.19/go.mod h1:wz5bfUIGYkED8Hqz9CdsW0o2jSgagotbVLOCbHHacSI= github.com/MontFerret/barn v1.4.0 h1:68L+WFVxqPKuxuAj5f8CLBDmo/xnv6q0sxl4+GrrDmc= github.com/MontFerret/barn v1.4.0/go.mod h1:7+5uWWREpGgGppWjiEf8qCQuZyf+QshDr8zy4XaFSlA= github.com/MontFerret/contrib/modules/ai/llm v1.0.0-rc.6 h1:d3F2WWcGdTmYVXfNTTFVXDEonWpTSfmcde2GzOFsGgE= @@ -50,8 +50,8 @@ github.com/MontFerret/contrib/pkg/common v0.2.0 h1:/ftEguEPPg7tGTAHUkTzu4y+nW234 github.com/MontFerret/contrib/pkg/common v0.2.0/go.mod h1:bgwvpoX6xgEIWRQvEmftgsgbs2JER0DHqMqXqyuWq6E= github.com/MontFerret/cssx v0.2.0 h1:De0C6Irbg+qgFPXgWmPpVnwD4RRYUBQSbIYFTUVCNWU= github.com/MontFerret/cssx v0.2.0/go.mod h1:fmGtRUNVaeJYpiPSDlNIbbYzb3+K8NxmNmJOYqlHATU= -github.com/MontFerret/ferret/v2 v2.0.0-alpha.54 h1:Csrf/CEsqmuSp0s/nDbnnkmXQtIHuWVLCuzGNNUlFu4= -github.com/MontFerret/ferret/v2 v2.0.0-alpha.54/go.mod h1:6okTqyD30H5pCa8yXHQfpEzgRZWAsHgx68K6DTcDHek= +github.com/MontFerret/ferret/v2 v2.0.0-alpha.55 h1:ylh5oXP8smLSo9P40a52bOQWBF9kk8EAIe6/atWWsck= +github.com/MontFerret/ferret/v2 v2.0.0-alpha.55/go.mod h1:wjyA9O+zZHXn5+izgqOhuhkdHk9irwL8YsUKPCRRNRk= github.com/MontFerret/specs v1.12.0 h1:1HaElGLN+tyZIsrb3WVdulxbW5W0LXEdOH0k6F1sFzk= github.com/MontFerret/specs v1.12.0/go.mod h1:ENGyEPFjrWVPWOUAsBMc1acUsqpswieTrAJfhcm576E= github.com/PuerkitoBio/goquery v1.13.0 h1:mqHbjD7Jmnul4DTR24LKTjo1uUmHUh072kteGV+xpFM= diff --git a/pkg/debugger/fake_line_reader_test.go b/pkg/debugger/fake_line_reader_test.go new file mode 100644 index 0000000..2f2cff6 --- /dev/null +++ b/pkg/debugger/fake_line_reader_test.go @@ -0,0 +1,23 @@ +package debugger + +import "io" + +type lineResult struct { + line string + err error +} + +type fakeLineReader struct { + results []lineResult + index int +} + +func (f *fakeLineReader) Readline() (string, error) { + if f.index >= len(f.results) { + return "", io.EOF + } + + result := f.results[f.index] + f.index++ + return result.line, result.err +} diff --git a/pkg/debugger/fake_session_test.go b/pkg/debugger/fake_session_test.go new file mode 100644 index 0000000..7f453b1 --- /dev/null +++ b/pkg/debugger/fake_session_test.go @@ -0,0 +1,141 @@ +package debugger + +import ( + "context" + + "github.com/MontFerret/ferret/v2" + ferruntime "github.com/MontFerret/ferret/v2/pkg/runtime" + "github.com/MontFerret/ferret/v2/pkg/source" +) + +type fakeSession struct { + startEvent *ferret.DebugEvent + continueEvent *ferret.DebugEvent + locals []ferret.DebugVariable + frames []ferret.DebugFrame + breakpoints []ferret.DebugBreakpoint + evaluation ferret.DebugValue + continueErr error + evaluateErr error + breakpointsErr error + contexts map[CommandName]context.Context + expression string + closeErr error + breakpointLocation ferret.DebugSourceLocation + breakpointOptions ferret.DebugBreakpointOptions + startCalls int + continueCalls int + stepCalls int + nextCalls int + outCalls int + pauseCalls int + setBreakpointCalls int + deleteCalls int + breakpointsCalls int + framesCalls int + localsCalls int + evaluateCalls int + closeCalls int +} + +func (f *fakeSession) Start(context.Context) (*ferret.DebugEvent, error) { + f.startCalls++ + return f.startEvent, nil +} + +func (f *fakeSession) Continue(context.Context) (*ferret.DebugEvent, error) { + f.continueCalls++ + return f.continueEvent, f.continueErr +} + +func (f *fakeSession) StepIn(context.Context) (*ferret.DebugEvent, error) { + f.stepCalls++ + return f.continueEvent, nil +} + +func (f *fakeSession) StepOver(context.Context) (*ferret.DebugEvent, error) { + f.nextCalls++ + return f.continueEvent, nil +} + +func (f *fakeSession) StepOut(context.Context) (*ferret.DebugEvent, error) { + f.outCalls++ + return f.continueEvent, nil +} + +func (f *fakeSession) Pause(ctx context.Context) error { + f.pauseCalls++ + f.recordContext(ctx, CommandPause) + + return nil +} + +func (f *fakeSession) SetBreakpointAt(ctx context.Context, location ferret.DebugSourceLocation, options ferret.DebugBreakpointOptions) (ferret.DebugBreakpoint, error) { + f.setBreakpointCalls++ + f.recordContext(ctx, CommandBreak) + f.breakpointLocation = location + f.breakpointOptions = options + breakpoint := ferret.DebugBreakpoint{ + ID: ferret.DebugBreakpointID(len(f.breakpoints) + 1), + RequestedLocation: location, + Location: debugLocation(location.SourceName, location.Line, location.Column, source.Span{}), + BindingMode: options.BindingMode, + Bound: true, + } + f.breakpoints = append(f.breakpoints, breakpoint) + return breakpoint, nil +} + +func (f *fakeSession) DeleteBreakpoint(ctx context.Context, id ferret.DebugBreakpointID) error { + f.deleteCalls++ + f.recordContext(ctx, CommandDelete) + + for i, breakpoint := range f.breakpoints { + if breakpoint.ID == id { + f.breakpoints = append(f.breakpoints[:i], f.breakpoints[i+1:]...) + return nil + } + } + + return ferruntime.Errorf(ferruntime.ErrNotFound, "breakpoint %d", id) +} + +func (f *fakeSession) Breakpoints(ctx context.Context) ([]ferret.DebugBreakpoint, error) { + f.breakpointsCalls++ + f.recordContext(ctx, CommandBreakpoints) + + return f.breakpoints, f.breakpointsErr +} + +func (f *fakeSession) Frames(ctx context.Context) ([]ferret.DebugFrame, error) { + f.framesCalls++ + f.recordContext(ctx, CommandWhere) + + return f.frames, nil +} + +func (f *fakeSession) Locals(ctx context.Context) ([]ferret.DebugVariable, error) { + f.localsCalls++ + f.recordContext(ctx, CommandLocals) + + return f.locals, nil +} + +func (f *fakeSession) Evaluate(_ context.Context, expression string) (ferret.DebugValue, error) { + f.evaluateCalls++ + f.expression = expression + return f.evaluation, f.evaluateErr +} + +func (f *fakeSession) Close() error { + f.closeCalls++ + return f.closeErr +} + +func (f *fakeSession) recordContext(ctx context.Context, command CommandName) { + if f.contexts == nil { + f.contexts = make(map[CommandName]context.Context) + } + + f.contexts[command] = ctx +} diff --git a/pkg/debugger/prompt.go b/pkg/debugger/prompt.go index 49c77d8..48a1ade 100644 --- a/pkg/debugger/prompt.go +++ b/pkg/debugger/prompt.go @@ -122,15 +122,14 @@ func executeCommand(ctx context.Context, session Session, mainSourceName string, location.SourceName = mainSourceName } - breakpoint, err := session.SetBreakpointAt(location, command.BreakpointOptions) - + breakpoint, err := session.SetBreakpointAt(ctx, location, command.BreakpointOptions) if err != nil { renderer.Error("Breakpoint error", err) } else { renderer.BreakpointSet(breakpoint) } case CommandDelete: - if err := session.DeleteBreakpoint(command.BreakpointID); err != nil { + if err := session.DeleteBreakpoint(ctx, command.BreakpointID); err != nil { if errors.Is(err, runtime.ErrNotFound) { fmt.Fprintf(renderer.out, "Unknown breakpoint: %d\n", command.BreakpointID) } else { @@ -140,7 +139,12 @@ func executeCommand(ctx context.Context, session Session, mainSourceName string, fmt.Fprintf(renderer.out, "Breakpoint %d deleted.\n", command.BreakpointID) } case CommandBreakpoints: - renderer.Breakpoints(session.Breakpoints()) + breakpoints, err := session.Breakpoints(ctx) + if err != nil { + renderer.Error("Breakpoints error", err) + } else { + renderer.Breakpoints(breakpoints) + } case CommandContinue: event, err := session.Continue(ctx) return false, renderResume(event, err, renderer) @@ -154,22 +158,20 @@ func executeCommand(ctx context.Context, session Session, mainSourceName string, event, err := session.StepOut(ctx) return false, renderResume(event, err, renderer) case CommandPause: - if err := session.Pause(); err != nil { + if err := session.Pause(ctx); err != nil { renderer.Error("Pause error", err) } else { fmt.Fprintln(renderer.out, "Pause requested.") } case CommandWhere: - frames, err := session.Frames() - + frames, err := session.Frames(ctx) if err != nil { renderer.Error("Stack error", err) } else { renderer.Frames(frames) } case CommandLocals: - locals, err := session.Locals() - + locals, err := session.Locals(ctx) if err != nil { renderer.Error("Locals error", err) } else { diff --git a/pkg/debugger/prompt_test.go b/pkg/debugger/prompt_test.go index 9cf664f..d3e8cc7 100644 --- a/pkg/debugger/prompt_test.go +++ b/pkg/debugger/prompt_test.go @@ -11,11 +11,11 @@ import ( "github.com/chzyer/readline" "github.com/MontFerret/ferret/v2" - ferruntime "github.com/MontFerret/ferret/v2/pkg/runtime" "github.com/MontFerret/ferret/v2/pkg/source" ) func TestRunDispatchesCommandsAndClosesSession(t *testing.T) { + ctx := t.Context() src := source.New("demo.fql", "LET x = 1\nRETURN x") session := &fakeSession{ startEvent: debugEvent(ferret.DebugReasonEntry, "demo.fql", 1, source.Span{Start: 0, End: 3}), @@ -43,10 +43,16 @@ func TestRunDispatchesCommandsAndClosesSession(t *testing.T) { }} var out bytes.Buffer - if err := Run(context.Background(), session, src, input, &out); err != nil { + if err := Run(ctx, session, src, input, &out); err != nil { t.Fatal(err) } + for _, command := range []CommandName{CommandBreak, CommandDelete, CommandBreakpoints, CommandPause, CommandWhere, CommandLocals} { + if got := session.contexts[command]; got != ctx { + t.Fatalf("command %v received context %v, want caller context", command, got) + } + } + if session.startCalls != 1 || session.pauseCalls != 1 || session.continueCalls != 1 || session.stepCalls != 1 || session.nextCalls != 1 || session.outCalls != 1 || session.closeCalls != 1 { t.Fatalf("unexpected session calls: %#v", session) @@ -116,6 +122,45 @@ func TestRunReportsCommandErrorsAndContinues(t *testing.T) { } } +func TestRunReportsBreakpointListErrorsAndContinues(t *testing.T) { + for _, test := range []struct { + name string + breakpoints []ferret.DebugBreakpoint + }{ + {name: "empty result"}, + {name: "partial result", breakpoints: []ferret.DebugBreakpoint{{ID: 1}}}, + } { + t.Run(test.name, func(t *testing.T) { + session := &fakeSession{ + startEvent: debugEvent(ferret.DebugReasonEntry, "demo.fql", 1, source.Span{Start: 0, End: 1}), + breakpoints: test.breakpoints, + breakpointsErr: context.Canceled, + } + var out bytes.Buffer + + err := Run(t.Context(), session, source.New("demo.fql", "RETURN 1"), &fakeLineReader{ + results: []lineResult{{line: "breakpoints"}, {line: "locals"}, {line: "q"}}, + }, &out) + if err != nil { + t.Fatal(err) + } + + if session.breakpointsCalls != 1 || session.localsCalls != 1 || session.closeCalls != 1 { + t.Fatalf("unexpected session calls: %#v", session) + } + + got := out.String() + if !strings.Contains(got, "Breakpoints error: context canceled") { + t.Fatalf("missing breakpoint-list error in %q", got) + } + + if strings.Contains(got, "No breakpoints.") || strings.Contains(got, "Requested") { + t.Fatalf("rendered breakpoint list after failure: %q", got) + } + }) + } +} + func TestRunEOFAndCloseError(t *testing.T) { closeErr := errors.New("close failed") session := &fakeSession{ @@ -383,135 +428,6 @@ func TestRunResumeErrorPreservesState(t *testing.T) { } } -type lineResult struct { - line string - err error -} - -type fakeLineReader struct { - results []lineResult - index int -} - -func (f *fakeLineReader) Readline() (string, error) { - if f.index >= len(f.results) { - return "", io.EOF - } - result := f.results[f.index] - f.index++ - return result.line, result.err -} - -type fakeSession struct { - startEvent *ferret.DebugEvent - continueEvent *ferret.DebugEvent - locals []ferret.DebugVariable - frames []ferret.DebugFrame - breakpoints []ferret.DebugBreakpoint - evaluation ferret.DebugValue - continueErr error - evaluateErr error - expression string - closeErr error - breakpointLocation ferret.DebugSourceLocation - breakpointOptions ferret.DebugBreakpointOptions - startCalls int - continueCalls int - stepCalls int - nextCalls int - outCalls int - pauseCalls int - setBreakpointCalls int - deleteCalls int - breakpointsCalls int - framesCalls int - localsCalls int - evaluateCalls int - closeCalls int -} - -func (f *fakeSession) Start(context.Context) (*ferret.DebugEvent, error) { - f.startCalls++ - return f.startEvent, nil -} - -func (f *fakeSession) Continue(context.Context) (*ferret.DebugEvent, error) { - f.continueCalls++ - return f.continueEvent, f.continueErr -} - -func (f *fakeSession) StepIn(context.Context) (*ferret.DebugEvent, error) { - f.stepCalls++ - return f.continueEvent, nil -} - -func (f *fakeSession) StepOver(context.Context) (*ferret.DebugEvent, error) { - f.nextCalls++ - return f.continueEvent, nil -} - -func (f *fakeSession) StepOut(context.Context) (*ferret.DebugEvent, error) { - f.outCalls++ - return f.continueEvent, nil -} - -func (f *fakeSession) Pause() error { - f.pauseCalls++ - return nil -} - -func (f *fakeSession) SetBreakpointAt(location ferret.DebugSourceLocation, options ferret.DebugBreakpointOptions) (ferret.DebugBreakpoint, error) { - f.setBreakpointCalls++ - f.breakpointLocation = location - f.breakpointOptions = options - breakpoint := ferret.DebugBreakpoint{ - ID: ferret.DebugBreakpointID(len(f.breakpoints) + 1), - RequestedLocation: location, - Location: debugLocation(location.SourceName, location.Line, location.Column, source.Span{}), - BindingMode: options.BindingMode, - Bound: true, - } - f.breakpoints = append(f.breakpoints, breakpoint) - return breakpoint, nil -} - -func (f *fakeSession) DeleteBreakpoint(id ferret.DebugBreakpointID) error { - f.deleteCalls++ - for i, breakpoint := range f.breakpoints { - if breakpoint.ID == id { - f.breakpoints = append(f.breakpoints[:i], f.breakpoints[i+1:]...) - return nil - } - } - return ferruntime.Errorf(ferruntime.ErrNotFound, "breakpoint %d", id) -} - -func (f *fakeSession) Breakpoints() []ferret.DebugBreakpoint { - f.breakpointsCalls++ - return f.breakpoints -} - -func (f *fakeSession) Frames() ([]ferret.DebugFrame, error) { - f.framesCalls++ - return f.frames, nil -} - -func (f *fakeSession) Locals() ([]ferret.DebugVariable, error) { - f.localsCalls++ - return f.locals, nil -} - -func (f *fakeSession) Evaluate(_ context.Context, expression string) (ferret.DebugValue, error) { - f.evaluateCalls++ - f.expression = expression - return f.evaluation, f.evaluateErr -} - -func (f *fakeSession) Close() error { - f.closeCalls++ - return f.closeErr -} - func debugEvent(reason ferret.DebugReason, file string, line int, span source.Span) *ferret.DebugEvent { return &ferret.DebugEvent{ Reason: reason, diff --git a/pkg/debugger/session.go b/pkg/debugger/session.go index 6bfe2e1..ee7b9ee 100644 --- a/pkg/debugger/session.go +++ b/pkg/debugger/session.go @@ -8,19 +8,20 @@ import ( type ( // Session is the core debugger contract consumed by the CLI. Run closes the - // session when the interactive loop exits. + // session when the interactive loop exits. Operations receive the caller's + // context, which must be non-nil, and preserve core cancellation behavior. Session interface { Start(context.Context) (*ferret.DebugEvent, error) Continue(context.Context) (*ferret.DebugEvent, error) StepIn(context.Context) (*ferret.DebugEvent, error) StepOver(context.Context) (*ferret.DebugEvent, error) StepOut(context.Context) (*ferret.DebugEvent, error) - Pause() error - SetBreakpointAt(ferret.DebugSourceLocation, ferret.DebugBreakpointOptions) (ferret.DebugBreakpoint, error) - DeleteBreakpoint(ferret.DebugBreakpointID) error - Breakpoints() []ferret.DebugBreakpoint - Frames() ([]ferret.DebugFrame, error) - Locals() ([]ferret.DebugVariable, error) + Pause(context.Context) error + SetBreakpointAt(context.Context, ferret.DebugSourceLocation, ferret.DebugBreakpointOptions) (ferret.DebugBreakpoint, error) + DeleteBreakpoint(context.Context, ferret.DebugBreakpointID) error + Breakpoints(context.Context) ([]ferret.DebugBreakpoint, error) + Frames(context.Context) ([]ferret.DebugFrame, error) + Locals(context.Context) ([]ferret.DebugVariable, error) Evaluate(context.Context, string) (ferret.DebugValue, error) Close() error } diff --git a/pkg/runtime/debug_context_test.go b/pkg/runtime/debug_context_test.go new file mode 100644 index 0000000..46a7b4b --- /dev/null +++ b/pkg/runtime/debug_context_test.go @@ -0,0 +1,86 @@ +package runtime + +import ( + "context" + "errors" + "slices" + "testing" + + "github.com/MontFerret/ferret/v2" + "github.com/MontFerret/ferret/v2/pkg/source" +) + +func TestDebugSessionCanceledOperationsPreserveBreakpoints(t *testing.T) { + ctx := t.Context() + + session, err := NewDebugSession(ctx, NewDefaultOptions(), nil, source.New("debug.fql", "LET value = 1\nRETURN value")) + if err != nil { + t.Fatal(err) + } + + t.Cleanup(func() { + if err := session.Close(); err != nil { + t.Error(err) + } + }) + + location := ferret.DebugSourceLocation{Position: ferret.Position{Line: 2}} + options := ferret.DebugBreakpointOptions{BindingMode: ferret.DebugBreakpointBindExact} + + breakpoint, err := session.SetBreakpointAt(ctx, location, options) + if err != nil { + t.Fatal(err) + } + + if !breakpoint.Bound { + t.Fatal("expected a bound breakpoint") + } + + if _, err := session.Start(ctx); err != nil { + t.Fatal(err) + } + + canceled, cancel := context.WithCancel(ctx) + cancel() + + for _, test := range []struct { + name string + run func(context.Context) error + }{ + {name: "pause", run: session.Pause}, + {name: "add", run: func(ctx context.Context) error { + _, err := session.SetBreakpointAt(ctx, location, options) + return err + }}, + {name: "delete", run: func(ctx context.Context) error { + return session.DeleteBreakpoint(ctx, breakpoint.ID) + }}, + {name: "list", run: func(ctx context.Context) error { + _, err := session.Breakpoints(ctx) + return err + }}, + {name: "frames", run: func(ctx context.Context) error { + _, err := session.Frames(ctx) + return err + }}, + {name: "locals", run: func(ctx context.Context) error { + _, err := session.Locals(ctx) + return err + }}, + } { + t.Run(test.name, func(t *testing.T) { + if err := test.run(canceled); !errors.Is(err, context.Canceled) { + t.Fatalf("expected cancellation, got %v", err) + } + + breakpoints, err := session.Breakpoints(ctx) + if err != nil { + t.Fatal(err) + } + + if !slices.Equal(breakpoints, []ferret.DebugBreakpoint{breakpoint}) { + t.Fatalf("canceled operation changed breakpoints: %#v", breakpoints) + } + }) + } +} diff --git a/pkg/runtime/debug_test.go b/pkg/runtime/debug_test.go index d83f677..0d5a6a1 100644 --- a/pkg/runtime/debug_test.go +++ b/pkg/runtime/debug_test.go @@ -25,6 +25,7 @@ func TestNewDebugSessionIntegration(t *testing.T) { defer session.Close() nextBreakpoint, err := session.SetBreakpointAt( + ctx, ferret.DebugSourceLocation{Position: ferret.Position{Line: 3}}, ferret.DebugBreakpointOptions{BindingMode: ferret.DebugBreakpointBindNextExecutableInSource}, ) @@ -35,6 +36,7 @@ func TestNewDebugSessionIntegration(t *testing.T) { t.Fatalf("unexpected next breakpoint: %#v", nextBreakpoint) } exactBreakpoint, err := session.SetBreakpointAt( + ctx, ferret.DebugSourceLocation{Position: ferret.Position{Line: 3}}, ferret.DebugBreakpointOptions{BindingMode: ferret.DebugBreakpointBindExact}, ) @@ -45,6 +47,7 @@ func TestNewDebugSessionIntegration(t *testing.T) { t.Fatalf("expected exact breakpoint to remain unbound: %#v", exactBreakpoint) } functionBreakpoint, err := session.SetBreakpointAt( + ctx, ferret.DebugSourceLocation{Position: ferret.Position{Line: 3}}, ferret.DebugBreakpointOptions{BindingMode: ferret.DebugBreakpointBindNextExecutableInFunction}, )