tests(f2/repl): migrate debugger tests

Change-Id: I2cc1d45db2e5e0b8cea6798c70e13ede57fea6ee
This commit is contained in:
rootile
2026-06-11 16:19:20 +02:00
parent ab149a6cd8
commit f7ce20d879
22 changed files with 546 additions and 351 deletions
@@ -1,113 +0,0 @@
@args --debugger
:c at the root repl is not allowed since no debugger is running yet
nix-repl> :c
error: command 'c' can only be used when the debugger is active
:c and other commands become available once a debugger starts
nix-repl> with {}; a
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
nix-repl> :?
The following commands are available:
<expr> Evaluate and print expression
<x> = <expr> Bind expression to variable
:?, :help Print help about all commands (this content)
:a, :add <expr> Add attributes from resulting set to scope
:b, :build <expr> Build a derivation
:bl, :build-with-gc-roots <expr> Build a derivation, creating GC roots in the working directory
:doc <expr> Show documentation for the provided function (experimental lambda support)
:e, :edit <expr> Open package or function in $EDITOR
:env Show environment stack
:i, :build-and-install <expr> Build derivation, then install result into current profile
:l, :load <path> Load Nix expression and add it to scope
:log <expr | .drv path> Show logs for a derivation
:p, :print <expr> Evaluate and print expression recursively
Strings are printed directly, without escaping.
:q, :quit Exit the REPL
:r, :reload Reload all files successfully loaded
:sh, :shell <expr> Build dependencies of derivation, then start nix-shell
:t, :type <expr> Describe result of evaluation
:te, :trace-enable [bool] Enable, disable, or toggle showing traces for errors
:u, :use <expr> Build derivation, then start nix-shell
Debug mode commands
:bt, :backtrace Show trace stack
:c, :continue Go until end of program, exception or builtins.break
:s, :step Go one step
:st, :show-trace [integer index] Show current trace. If an integer is provided, this switches to that stack beforehand. If the integer has an explicit + or - sign, it is treated as relative to the current stack index.
Flakes commands
:lf, :load-flake <flakeref> Load Nix flake and add it to the scope
we can now inspect state
nix-repl> :bt
1: error: Fake frame for debugging purposes
«string»:1:10
1| with {}; a
| ^
0: error: undefined variable 'a'
«string»:1:10
1| with {}; a
| ^
and resume execution
nix-repl> :c
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
the debugger is once again disabled
nix-repl> :c
error: command 'c' can only be used when the debugger is active
leaving the debugger from a toplevel error and entering it again doesn't leave old frames visible
nix-repl> with {}; a
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
nix-repl> :s
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
nix-repl> with {}; b
error: undefined variable 'b'
at «string»:1:10:
1| with {}; b
| ^
nix-repl> :bt
1: error: Fake frame for debugging purposes
«string»:1:10
1| with {}; b
| ^
0: error: undefined variable 'b'
«string»:1:10
1| with {}; b
| ^
exiting from here prints the error
nix-repl> :q
error: undefined variable 'b'
at «string»:1:10:
1| with {}; b
| ^
@@ -1,11 +0,0 @@
@args --debugger --no-ignore-try
we should enter a debug repl through tryEval
nix-repl> (builtins.tryEval ((x: throw "foo") 1)).success
error: foo
This exception occurred in a 'tryEval' call. Use --ignore-try to skip these.
no segfault either
nix-repl> :quit
error: foo
@@ -1,8 +0,0 @@
@args --debugger
we don't enter a debug repl through tryEval
nix-repl> (builtins.tryEval ((x: throw "foo") 1)).success
false
no segfault either
nix-repl> :quit
@@ -1,41 +0,0 @@
@args --debugger
we enter a debugger via builtins.break in the input file.
info: breakpoint reached
causing another debugger even should not nest, but simply
print the error, skip the breakpoint, etc as appropriate.
nix-repl> "values show"
"values show"
nix-repl> builtins.break 2
2
nix-repl> builtins.throw "foo"
error:
… caused by explicit throw
at «string»:1:1:
1| builtins.throw "foo"
| ^
error: foo
nix-repl> assert false; 2
error: assertion failed
at «string»:1:1:
1| assert false; 2
| ^
exiting the debug frame should allow another to open.
nix-repl> :c
nix-repl> builtins.throw "bar"
error: bar
and once again, more breakpoints are ignored.
nix-repl> builtins.break 3
3
error: bar
@@ -1,71 +0,0 @@
https://github.com/NixOS/nix/pull/9917 (Enter debugger more reliably in let expressions and function calls)
This test ensures that continues don't skip opportunities to enter the debugger.
@args --debugger
trace: before outer break
info: breakpoint reached
nix-repl> :c
trace: before inner break
info: breakpoint reached
nix-repl> :bt
6: while evaluating the file '$TEST_DATA/regression_9917.nix':
$TEST_DATA/regression_9917.nix:1:1
1| let
| ^
2| a = builtins.trace "before inner break" (
5: while evaluating a 'let' expression
$TEST_DATA/regression_9917.nix:1:1
1| let
| ^
2| a = builtins.trace "before inner break" (
4: while calling a function
$TEST_DATA/regression_9917.nix:5:7
4| );
5| b = builtins.trace "before outer break" (
| ^
6| builtins.break a
3: while calling a function
$TEST_DATA/regression_9917.nix:6:5
5| b = builtins.trace "before outer break" (
6| builtins.break a
| ^
7| );
2: while calling a function
$TEST_DATA/regression_9917.nix:2:7
1| let
2| a = builtins.trace "before inner break" (
| ^
3| builtins.break { msg = "hello"; }
1: while calling a function
$TEST_DATA/regression_9917.nix:3:5
2| a = builtins.trace "before inner break" (
3| builtins.break { msg = "hello"; }
| ^
4| );
0: error: breakpoint reached
$TEST_DATA/regression_9917.nix:3:5
2| a = builtins.trace "before inner break" (
3| builtins.break { msg = "hello"; }
| ^
4| );
nix-repl> :c
nix-repl> msg
"hello"
@@ -1,39 +0,0 @@
@args --debugger
error:
… while evaluating the error message passed to builtin.throw
error: cannot coerce a list to a string: [ ]
We expect to be able to see locals like r in the debugger:
nix-repl> r
[ ]
nix-repl> :env
Env level 0
static: r x
Env level 1
abort baseNameOf break builtins derivation derivationStrict dirOf false fetchGit fetchMercurial fetchTarball fetchTree fromTOML import isNull map null placeholder removeAttrs scopedImport throw toString true
nix-repl> :quit
error:
… while evaluating the file '$TEST_DATA/regression_9918.nix':
… while evaluating x
at $TEST_DATA/regression_9918.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'throw' builtin
at $TEST_DATA/regression_9918.nix:3:7:
2| r = [];
3| x = builtins.throw r;
| ^
4| in
(stack trace truncated; use '--show-trace' to show the full trace)
error: cannot coerce a list to a string: [ ]
@@ -1,39 +0,0 @@
@args --debugger
info: breakpoint reached
debugger should not crash now, but also not show any with variables
nix-repl> :st
0: error: breakpoint reached
$TEST_DATA/regression_l145.nix:3:7
2| let
3| x = builtins.break 1;
| ^
4| in
Env level 0
static: x
Env level 1
static:
Env level 2
abort baseNameOf break builtins derivation derivationStrict dirOf false fetchGit fetchMercurial fetchTarball fetchTree fromTOML import isNull map null placeholder removeAttrs scopedImport throw toString true
error:
… while evaluating the file '$TEST_DATA/regression_l145.nix':
… while evaluating x
at $TEST_DATA/regression_l145.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'break' builtin
at $TEST_DATA/regression_l145.nix:3:7:
2| let
3| x = builtins.break 1;
| ^
4| in
error: breakpoint reached
@@ -1,21 +0,0 @@
@args --debugger
info: breakpoint reached
nix-repl> :quit
error:
… while evaluating the file '$TEST_DATA/regression_l592.nix':
… while calling the 'seq' builtin
at $TEST_DATA/regression_l592.nix:1:15:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
… while calling the 'break' builtin
at $TEST_DATA/regression_l592.nix:1:36:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
error: breakpoint reached
@@ -176,11 +176,6 @@ TEST_F(ReplSessionTest, tidy)
runReplTestPath(#name); \
}
REPL_TEST(no_nested_debuggers);
REPL_TEST(regression_9917);
REPL_TEST(regression_9918);
REPL_TEST(regression_l145);
REPL_TEST(regression_l592);
REPL_TEST(repl_input);
REPL_TEST(repl_overlays);
REPL_TEST(repl_overlays_regression_l777);
@@ -191,9 +186,6 @@ REPL_TEST(repl_printing);
REPL_TEST(stack_vars);
REPL_TEST(errors);
REPL_TEST(idempotent);
REPL_TEST(debug_frames);
REPL_TEST(debug_ignore_try);
REPL_TEST(debug_ignore_try_defaults);
REPL_TEST(stacktrace_invalid_arg);
REPL_TEST(stacktrace_oob);
REPL_TEST(stacktrace_relative);
@@ -0,0 +1,162 @@
---
args: ['--debugger']
---
:c at the root repl is not allowed since no debugger is running yet
```nix
:c
```
```output
error: command 'c' can only be used when the debugger is active
```
:c and other commands become available once a debugger starts
```nix
with {}; a
```
```output
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
```
```nix
:?
```
```output
The following commands are available:
<expr> Evaluate and print expression
<x> = <expr> Bind expression to variable
:?, :help Print help about all commands (this content)
:a, :add <expr> Add attributes from resulting set to scope
:b, :build <expr> Build a derivation
:bl, :build-with-gc-roots <expr> Build a derivation, creating GC roots in the working directory
:doc <expr> Show documentation for the provided function (experimental lambda support)
:e, :edit <expr> Open package or function in $EDITOR
:env Show environment stack
:i, :build-and-install <expr> Build derivation, then install result into current profile
:l, :load <path> Load Nix expression and add it to scope
:log <expr | .drv path> Show logs for a derivation
:p, :print <expr> Evaluate and print expression recursively
Strings are printed directly, without escaping.
:q, :quit Exit the REPL
:r, :reload Reload all files successfully loaded
:sh, :shell <expr> Build dependencies of derivation, then start nix-shell
:t, :type <expr> Describe result of evaluation
:te, :trace-enable [bool] Enable, disable, or toggle showing traces for errors
:u, :use <expr> Build derivation, then start nix-shell
Debug mode commands
:bt, :backtrace Show trace stack
:c, :continue Go until end of program, exception or builtins.break
:s, :step Go one step
:st, :show-trace [integer index] Show current trace. If an integer is provided, this switches to that stack beforehand. If the integer has an explicit + or - sign, it is treated as relative to the current stack index.
Flakes commands
:lf, :load-flake <flakeref> Load Nix flake and add it to the scope
```
we can now inspect state
```nix
:bt
```
```output
1: error: Fake frame for debugging purposes
«string»:1:10
1| with {}; a
| ^
0: error: undefined variable 'a'
«string»:1:10
1| with {}; a
| ^
```
and resume execution
```nix
:c
```
```output
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
```
the debugger is once again disabled
```nix
:c
```
```output
error: command 'c' can only be used when the debugger is active
```
leaving the debugger from a toplevel error and entering it again doesn't leave old frames visible
```nix
with {}; a
:s
with {}; b
:bt
```
```output
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
error: undefined variable 'a'
at «string»:1:10:
1| with {}; a
| ^
error: undefined variable 'b'
at «string»:1:10:
1| with {}; b
| ^
1: error: Fake frame for debugging purposes
«string»:1:10
1| with {}; b
| ^
0: error: undefined variable 'b'
«string»:1:10
1| with {}; b
| ^
```
exiting from here prints the error
```nix
:q
```
```output
error: undefined variable 'b'
at «string»:1:10:
1| with {}; b
| ^
```
@@ -0,0 +1,26 @@
---
args: ['--debugger', '--no-ignore-try']
---
we should enter a debug repl through `tryEval`
```nix
(builtins.tryEval ((x: throw "foo") 1)).success
```
```output
error: foo
This exception occurred in a 'tryEval' call. Use --ignore-try to skip these.
Added 1 variables.
```
no segfaults either
```nix
:quit
```
```output
error: foo
```
@@ -0,0 +1,21 @@
---
args: ['--debugger']
---
we don't enter a debug repl through tryEval
```nix
(builtins.tryEval ((x: throw "foo") 1)).success
```
```output
false
```
no segfault either
```nix
:quit
```
```output
```
@@ -0,0 +1,70 @@
---
args: ['--debugger', '-f', 'no_nested_debuggers.nix']
files: ['no_nested_debuggers.nix']
---
```output
Lix VERSION
Type :? for help.
info: breakpoint reached
```
we enter a debugger via builtins.break in the input file.
```nix
"values show"
```
```output
"values show"
```
causing another debugger even should not nest, but simply print the error, skip the breakpoint, etc as appropriate
```nix
builtins.break 2
builtins.throw "foo"
assert false; 2
```
```output
2
error:
… caused by explicit throw
at «string»:1:1:
1| builtins.throw "foo"
| ^
error: foo
error: assertion failed
at «string»:1:1:
1| assert false; 2
| ^
```
exiting the debugger frame should allow another to open.
```nix
:c
builtins.throw "bar"
```
```output
Loading installable ''...
error: bar
```
and once again, more breakpoints are ignored.
```nix
builtins.break 3
```
```output
3
```
@@ -0,0 +1,95 @@
---
args: ['--debugger', '-f', 'regression_9917.nix']
files: ['regression_9917.nix']
---
https://github.com/NixOS/nix/pull/9917 (Enter debugger more reliably in let expressions and function calls)
```output
Lix VERSION
Type :? for help.
trace: before outer break
info: breakpoint reached
Added 2 variables.
```
This test ensures that continues don't skip opportunities to enter the debugger.
```nix
:c
:bt
```
```output
trace: before inner break
info: breakpoint reached
Added 2 variables.
6: while evaluating the file '/pwd/regression_9917.nix':
/pwd/regression_9917.nix:1:1
1| let
| ^
2| a = builtins.trace "before inner break" (
5: while evaluating a 'let' expression
/pwd/regression_9917.nix:1:1
1| let
| ^
2| a = builtins.trace "before inner break" (
4: while calling a function
/pwd/regression_9917.nix:5:7
4| );
5| b = builtins.trace "before outer break" (
| ^
6| builtins.break a
3: while calling a function
/pwd/regression_9917.nix:6:5
5| b = builtins.trace "before outer break" (
6| builtins.break a
| ^
7| );
2: while calling a function
/pwd/regression_9917.nix:2:7
1| let
2| a = builtins.trace "before inner break" (
| ^
3| builtins.break { msg = "hello"; }
1: while calling a function
/pwd/regression_9917.nix:3:5
2| a = builtins.trace "before inner break" (
3| builtins.break { msg = "hello"; }
| ^
4| );
0: error: breakpoint reached
/pwd/regression_9917.nix:3:5
2| a = builtins.trace "before inner break" (
3| builtins.break { msg = "hello"; }
| ^
4| );
```
```nix
:c
msg
```
```output
Loading installable ''...
Added 1 variables.
"hello"
```
@@ -0,0 +1,59 @@
---
args: ['--debugger', '-f', 'regression_9918.nix']
should_fail: True
files: ['regression_9918.nix']
---
```output
Lix VERSION
Type :? for help.
error:
… while evaluating the error message passed to builtin.throw
error: cannot coerce a list to a string: [ ]
Added 2 variables.
```
We expect to be able to see locals like `r` in the debugger:
```nix
r
:env
```
```output
[ ]
Env level 0
static: r x
Env level 1
abort baseNameOf break builtins derivation derivationStrict dirOf false fetchGit fetchMercurial fetchTarball fetchTree fromTOML import isNull map null placeholder removeAttrs scopedImport throw toString true
```
```nix
:quit
```
```output
error:
… while evaluating the file '/pwd/regression_9918.nix':
… while evaluating x
at /pwd/regression_9918.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'throw' builtin
at /pwd/regression_9918.nix:3:7:
2| r = [];
3| x = builtins.throw r;
| ^
4| in
… while evaluating the error message passed to builtin.throw
error: cannot coerce a list to a string: [ ]
```
@@ -0,0 +1,65 @@
---
args: ['--debugger', '-f', 'regression_l145.nix']
should_fail: True
files: ['regression_l145.nix']
---
```output
Lix VERSION
Type :? for help.
info: breakpoint reached
Added 1 variables.
```
debugger should not crash now, but also not show any `with` variables
```nix
:st
```
```output
0: error: breakpoint reached
/pwd/regression_l145.nix:3:7
2| let
3| x = builtins.break 1;
| ^
4| in
Env level 0
static: x
Env level 1
static:
Env level 2
abort baseNameOf break builtins derivation derivationStrict dirOf false fetchGit fetchMercurial fetchTarball fetchTree fromTOML import isNull map null placeholder removeAttrs scopedImport throw toString true
Added 1 variables.
```
```nix
:quit
```
```output
error:
… while evaluating the file '/pwd/regression_l145.nix':
… while evaluating x
at /pwd/regression_l145.nix:5:3:
4| in
5| x
| ^
6|
… while calling the 'break' builtin
at /pwd/regression_l145.nix:3:7:
2| let
3| x = builtins.break 1;
| ^
4| in
error: breakpoint reached
```
@@ -0,0 +1,48 @@
---
args: ['--debugger', '-f', 'regression_l592.nix']
should_fail: True
files: ['regression_l592.nix']
---
```output
Lix VERSION
Type :? for help.
info: breakpoint reached
Added 1 variables.
```
the with caused a crash with empty things
```nix
:quit
```
```output
error:
… while evaluating the file '/pwd/regression_l592.nix':
… while calling the 'seq' builtin
at /pwd/regression_l592.nix:1:15:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
… from call site
at /pwd/regression_l592.nix:1:32:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
… while calling anonymous lambda
at /pwd/regression_l592.nix:1:33:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
… while calling the 'break' builtin
at /pwd/regression_l592.nix:1:36:
1| let x = 4; in __seq x (with x; (x: builtins.break x) 1)
| ^
2|
error: breakpoint reached
```