xref: /openbsd/gnu/usr.bin/perl/lib/perl5db.t (revision 3d61058a)
1#!./perl
2
3BEGIN {
4    chdir 't' if -d 't';
5    @INC = '../lib';
6    require './test.pl';
7}
8
9use strict;
10use warnings;
11use Config;
12
13delete $ENV{PERLDB_OPTS};
14
15BEGIN {
16    if (! -c "/dev/null") {
17        print "1..0 # Skip: no /dev/null\n";
18        exit 0;
19    }
20
21    my $dev_tty = '/dev/tty';
22    $dev_tty = 'TT:' if ($^O eq 'VMS');
23    if (! -c $dev_tty) {
24        print "1..0 # Skip: no $dev_tty\n";
25        exit 0;
26    }
27    if ($ENV{PERL5DB}) {
28        print "1..0 # Skip: \$ENV{PERL5DB} is already set to '$ENV{PERL5DB}'\n";
29        exit 0;
30    }
31    $ENV{PERL_RL} = 'Perl'; # Suppress system Term::ReadLine::Gnu
32}
33
34my $rc_filename = '.perldb';
35
36sub rc {
37    open my $rc_fh, '>', $rc_filename
38        or die $!;
39    print {$rc_fh} @_;
40    close ($rc_fh);
41
42    # overly permissive perms gives "Must not source insecure rcfile"
43    # and hangs at the DB(1> prompt
44    chmod 0644, $rc_filename;
45}
46
47sub _slurp
48{
49    my $filename = shift;
50
51    open my $in, '<', $filename
52        or die "Cannot open '$filename' for slurping - $!";
53
54    local $/;
55    my $contents = <$in>;
56
57    close($in);
58
59    return $contents;
60}
61
62my $out_fn = 'db.out';
63
64sub _out_contents
65{
66    return _slurp($out_fn);
67}
68
69
70# Test for Proxy constants
71{
72    rc(
73        <<'EOF',
74
75&parse_options("NonStop=0 ReadLine=0 TTY=db.out");
76
77sub afterinit {
78    push(@DB::typeahead,
79        'm main->s1',
80        'q',
81    );
82}
83
84EOF
85    );
86
87    my $output = runperl(switches => [ '-d' ], stderr => 1, progfile => '../lib/perl5db/t/proxy-constants');
88    is($output, "", "proxy constant subroutines");
89}
90
91# [perl #66110] Call a subroutine inside a regex
92{
93    local $ENV{PERLDB_OPTS} = "ReadLine=0 NonStop=1";
94    my $output = runperl(switches => [ '-d' ], stderr => 1, progfile => '../lib/perl5db/t/rt-66110');
95    like($output, qr/\bAll tests successful\.$/, "[perl #66110]");
96}
97# [ perl #116769] Frame=2
98{
99    local $ENV{PERLDB_OPTS} = "frame=2 nonstop";
100    my $output = runperl( switches => [ '-d' ], prog => 'print qq{success\n}' );
101    is( $?, 0, '[perl #116769] frame=2 does not crash debugger, exit == 0' );
102    is( $output, "success\n" , '[perl #116769] code is run' );
103}
104# [ perl #116771] autotrace
105{
106    local $ENV{PERLDB_OPTS} = "autotrace nonstop";
107    my $output = runperl( switches => [ '-d' ], prog => 'print qq{success\n}' );
108    is( $?, 0, '[perl #116771] autotrace does not crash debugger, exit == 0' );
109    is( $output, "success\n" , '[perl #116771] code is run' );
110}
111# [ perl #41461] Frame=2 noTTY
112{
113    local $ENV{PERLDB_OPTS} = "frame=2 noTTY nonstop";
114    rc('');
115    my $output = runperl( switches => [ '-d' ], prog => 'print qq{success\n}' );
116    is( $?, 0, '[perl #41461] frame=2 noTTY does not crash debugger, exit == 0' );
117    is( $output, "success\n" , '[perl #41461] code is run' );
118}
119
120package DebugWrap;
121
122sub new {
123    my $class = shift;
124
125    my $self = bless {}, $class;
126
127    $self->_init(@_);
128
129    return $self;
130}
131
132sub _cmds {
133    my $self = shift;
134
135    if (@_) {
136        $self->{_cmds} = shift;
137    }
138
139    return $self->{_cmds};
140}
141
142sub _prog {
143    my $self = shift;
144
145    if (@_) {
146        $self->{_prog} = shift;
147    }
148
149    return $self->{_prog};
150}
151
152sub _output {
153    my $self = shift;
154
155    if (@_) {
156        $self->{_output} = shift;
157    }
158
159    return $self->{_output};
160}
161
162sub _include_t
163{
164    my $self = shift;
165
166    if (@_)
167    {
168        $self->{_include_t} = shift;
169    }
170
171    return $self->{_include_t};
172}
173
174sub _stderr_val
175{
176    my $self = shift;
177
178    if (@_)
179    {
180        $self->{_stderr_val} = shift;
181    }
182
183    return $self->{_stderr_val};
184}
185
186sub field
187{
188    my $self = shift;
189
190    if (@_)
191    {
192        $self->{field} = shift;
193    }
194
195    return $self->{field};
196}
197
198sub _switches
199{
200    my $self = shift;
201
202    if (@_)
203    {
204        $self->{_switches} = shift;
205    }
206
207    return $self->{_switches};
208}
209
210sub _contents
211{
212    my $self = shift;
213
214    if (@_)
215    {
216        $self->{_contents} = shift;
217    }
218
219    return $self->{_contents};
220}
221
222# object for prog temporary file
223sub _tempprog
224{
225    my $self = shift;
226
227    if (@_)
228    {
229        $self->{_tempprog} = shift;
230    }
231
232    return $self->{_tempprog};
233}
234
235sub _init
236{
237    my ($self, $args) = @_;
238
239    my $cmds = $args->{cmds};
240
241    if (ref($cmds) ne 'ARRAY') {
242        die "cmds must be an array of commands.";
243    }
244
245    $self->_cmds($cmds);
246
247    my $prog = $args->{prog};
248
249    if (ref($prog) eq 'SCALAR') {
250        use File::Temp;
251        my $fh = File::Temp->new;
252        $self->_tempprog($fh);
253        print $fh $$prog;
254        $prog = $fh->filename;
255    }
256    elsif (ref($prog) ne '' or !defined($prog)) {
257        die "prog should be a path to a program file.";
258    }
259
260    $self->_prog($prog);
261
262    $self->_include_t($args->{include_t} ? 1 : 0);
263
264    $self->_stderr_val(exists($args->{stderr}) ? $args->{stderr} : 1);
265
266    if (exists($args->{switches}))
267    {
268        $self->_switches($args->{switches});
269    }
270
271    $self->_run();
272
273    return;
274}
275
276sub _quote
277{
278    my ($self, $str) = @_;
279
280    $str =~ s/(["\@\$\\])/\\$1/g;
281    $str =~ s/\n/\\n/g;
282    $str =~ s/\r/\\r/g;
283
284    return qq{"$str"};
285}
286
287sub _run {
288    my $self = shift;
289
290    my $rc = qq{&parse_options("NonStop=0 TTY=db.out");\n};
291
292    $rc .= join('',
293        map { "$_\n"}
294        (q#sub afterinit {#,
295         q#push (@DB::typeahead,#,
296         (map { $self->_quote($_) . "," } @{$self->_cmds()}),
297         q#);#,
298         q#}#,
299        )
300    );
301
302    # I guess two objects like that cannot be used at the same time.
303    # Oh well.
304    ::rc($rc);
305
306    my $output =
307        ::runperl(
308            switches =>
309            [
310                ($self->_switches ? (@{$self->_switches()}) : ('-d')),
311                ($self->_include_t ? ('-I', '../lib/perl5db/t') : ())
312            ],
313            (defined($self->_stderr_val())
314                ? (stderr => $self->_stderr_val())
315                : ()
316            ),
317            progfile => $self->_prog()
318        );
319
320    $self->_output($output);
321
322    $self->_contents(::_out_contents());
323
324    return;
325}
326
327sub get_output
328{
329    return shift->_output();
330}
331
332sub output_like {
333    my ($self, $re, $msg) = @_;
334
335    local $::Level = $::Level + 1;
336    ::like($self->_output(), $re, $msg);
337}
338
339sub output_unlike {
340    my ($self, $re, $msg) = @_;
341
342    local $::Level = $::Level + 1;
343    ::unlike($self->_output(), $re, $msg);
344}
345
346sub get_contents {
347    return shift->_contents();
348}
349
350sub contents_like {
351    my ($self, $re, $msg) = @_;
352
353    local $::Level = $::Level + 1;
354    ::like($self->_contents(), $re, $msg);
355}
356
357sub contents_unlike {
358    my ($self, $re, $msg) = @_;
359
360    local $::Level = $::Level + 1;
361    ::unlike($self->_contents(), $re, $msg);
362}
363
364=head1 NAME
365
366DebugWrap - wrapper to execute code under the debugger and examine the
367results.
368
369=head1 SYNOPSIS
370
371    my $wrapper = DebugWrap->new(
372        {
373            cmds =>
374            [
375                # list of commands supplied to the debugger
376            ],
377            prog => 'filename_of_code_to_debug.pl',
378            # and some optional arguments
379        }
380    );
381
382    my $wrapper = DebugWrap->new(
383        {
384            cmds =>
385            [
386                # list of commands supplied to the debugger
387            ],
388            prog => \<<'EOS',
389    # perl code to debug
390    EOS
391            # and some optional arguments
392        }
393    );
394
395    # test the output from the program being debugged
396    $wrapper->output_like(qr/.../, "describe the test");
397    $wrapper->output_unlike(qr/.../, "describe the test");
398    my $output = $wrapper->get_output; # for more sophisticated checks
399
400    # test the output from the debugger
401    $wrapper->contents_like(qr/.../, "describe the test");
402    $wrapper->contents_unlike(qr/.../, "describe the test");
403    my $contents = $wrapper->get_contents; # for more sophisticated checks
404
405=head1 DESCRIPTION
406
407DebugWrap is a simple class used when testing the Perl debugger that
408executes a set of debugger commands against a program under the
409debugger and provides some simple methods to examine the results.
410
411It is not installed to your system.
412
413=head2 Creating a DebugWrap object
414
415The constructor new() accepts a hash of arguments, with the following
416possible members:
417
418=over
419
420=item cmds
421
422An array of commands to execute, one command per element.  Required.
423
424=item prog
425
426Either the name of a perl program to test under the debugger, or a
427reference to a scalar containing the text of the program to test.
428Required.
429
430=item stderr
431
432If this is a true value capture standard error, which is the default.
433Optional.
434
435=item include_t
436
437Add F<lib/perl5db/t> to the perl search path, as with C<-I>
438
439=item switches
440
441An arrayref of switches to supply to perl.  This should include the
442C<-d> switch needed to invoke the debugger.  If C<switches> is not
443supplied then C<-d> only is supplied.  The C<-I> for C<include_t> is
444added after these switches.
445
446=back
447
448=head2 Other methods
449
450The other methods intended for test usage are:
451
452=over
453
454=item $wrapper->get_contents
455
456Fetch the debugger output from the debugger run.  This does not
457include the output from the program under test.
458
459=item $wrapper->contents_like($re, $test_name)
460
461Test that the debugger output matches the given regular expression
462object (as with qr//).
463
464Equivalent to:
465
466  like($wrapper->get_contents, $re, $test_name);
467
468=item $wrapper->contents_unlike($re, $test_name)
469
470Test that the debugger output does not match the given regular
471expression object (as with qr//).
472
473Equivalent to:
474
475  unlike($wrapper->get_contents, $re, $test_name);
476
477=item $wrapper->get_output
478
479Fetch the program output from the debugger run.  This does not include
480the output from the debugger itself, it does include the output
481generated by C<valgrind> or ASAN, assuming you haven't disabled
482capturing stderr.
483
484=item $wrapper->output_like($re, $test_name);
485
486Test that the program output matches the given regular expression
487object (as with qr//).
488
489Equivalent to:
490
491  like($wrapper->get_output, $re, $test_name);
492
493=item $wrapper->output_unlike($re, $test_name);
494
495Test that the program output does not match the given regular
496expression object (as with qr//).
497
498Equivalent to:
499
500  unlike($wrapper->get_output, $re, $test_name);
501
502=back
503
504=cut
505
506package main;
507
508{
509    local $ENV{PERLDB_OPTS} = "ReadLine=0";
510    my $target = '../lib/perl5db/t/eval-line-bug';
511    my $wrapper = DebugWrap->new(
512        {
513            cmds =>
514            [
515                'b 23',
516                'n',
517                'n',
518                'n',
519                'c', # line 23
520                'n',
521                "p \@{'main::_<$target'}",
522                'q',
523            ],
524            prog => $target,
525        }
526    );
527    $wrapper->contents_like(
528        qr/sub factorial/,
529        'The ${main::_<filename} variable in the debugger was not destroyed',
530    );
531}
532
533sub _calc_generic_wrapper
534{
535    my $args = shift;
536
537    my $extra_opts = delete($args->{extra_opts});
538    $extra_opts ||= '';
539    local $ENV{PERLDB_OPTS} = "ReadLine=0" . $extra_opts;
540    return DebugWrap->new(
541        {
542            cmds => delete($args->{cmds}),
543            prog => delete($args->{prog}),
544            %$args,
545        }
546    );
547}
548
549sub _calc_new_var_wrapper
550{
551    my ($args) = @_;
552    return _calc_generic_wrapper(
553        {
554            cmds =>
555            [
556                'b 23',
557                'c',
558                '$new_var = "Foo"',
559                'x "new_var = <$new_var>\\n"',
560                'q',
561            ],
562            %$args,
563        }
564    );
565}
566
567sub _calc_threads_wrapper
568{
569    my $args = shift;
570
571    return _calc_new_var_wrapper(
572        {
573            switches => [ '-dt', ],
574            stderr => 1,
575            %$args
576        }
577    );
578}
579
580{
581    _calc_new_var_wrapper({ prog => '../lib/perl5db/t/eval-line-bug'})
582        ->contents_like(
583            qr/new_var = <Foo>/,
584            "no strict 'vars' in evaluated lines.",
585        );
586}
587
588{
589    _calc_new_var_wrapper(
590        {
591            prog => '../lib/perl5db/t/lvalue-bug',
592            stderr => undef(),
593        },
594    )->output_like(
595            qr/foo is defined/,
596             'lvalue subs work in the debugger',
597         );
598}
599
600{
601    _calc_new_var_wrapper(
602        {
603            prog =>  '../lib/perl5db/t/symbol-table-bug',
604            extra_opts => "NonStop=1",
605            stderr => undef(),
606        }
607    )->output_like(
608        qr/Undefined symbols 0/,
609        'there are no undefined values in the symbol table',
610    );
611}
612
613SKIP:
614{
615    if ( $Config{usethreads} ) {
616        skip('This perl has threads, skipping non-threaded debugger tests');
617    }
618    else {
619        my $error = 'This Perl not built to support threads';
620        _calc_threads_wrapper(
621            {
622                prog => '../lib/perl5db/t/eval-line-bug',
623            }
624        )->output_like(
625            qr/\Q$error\E/,
626            'Perl debugger correctly complains that it was not built with threads',
627        );
628    }
629}
630
631SKIP:
632{
633    if ( $Config{usethreads} ) {
634        _calc_threads_wrapper(
635            {
636                prog =>  '../lib/perl5db/t/symbol-table-bug',
637            }
638        )->output_like(
639            qr/Undefined symbols 0/,
640            'there are no undefined values in the symbol table when running with thread support',
641        );
642    }
643    else {
644        skip("This perl is not threaded, skipping threaded debugger tests");
645    }
646}
647
648# Test [perl #61222]
649{
650    local $ENV{PERLDB_OPTS};
651    my $wrapper = DebugWrap->new(
652        {
653            cmds =>
654            [
655                'm Pie',
656                'q',
657            ],
658            prog => '../lib/perl5db/t/rt-61222',
659        }
660    );
661
662    $wrapper->contents_unlike(qr/INCORRECT/, "[perl #61222]");
663}
664
665sub _calc_trace_wrapper
666{
667    my ($args) = @_;
668
669    return _calc_generic_wrapper(
670        {
671            cmds =>
672            [
673                't 2',
674                'c',
675                'q',
676            ],
677            %$args,
678        }
679    );
680}
681
682# [perl 104168] level option for tracing
683{
684    my $wrapper = _calc_trace_wrapper({ prog =>  '../lib/perl5db/t/rt-104168' });
685    $wrapper->contents_like(qr/level 2/, "[perl #104168] - level 2 appears");
686    $wrapper->contents_unlike(qr/baz/, "[perl #104168] - no 'baz'");
687}
688
689# taint tests
690if (!exists($Config{taint_support}) || $Config{taint_support})
691{
692    my $wrapper = _calc_trace_wrapper(
693        {
694            prog => '../lib/perl5db/t/taint',
695            extra_opts => ' NonStop=1',
696            switches => [ '-d', '-T', ],
697        }
698    );
699
700    my $output = $wrapper->get_output();
701    chomp $output if $^O eq 'VMS'; # newline guaranteed at EOF
702    is($output, '[$^X][done]', "taint");
703}
704
705# Testing that we can set a line in the middle of the file.
706{
707    my $wrapper = DebugWrap->new(
708        {
709            cmds =>
710            [
711                'b ../lib/perl5db/t/MyModule.pm:12',
712                'c',
713                q/do { use IO::Handle; STDOUT->autoflush(1); print "Var=$var\n"; }/,
714                'c',
715                'q',
716            ],
717            include_t => 1,
718            prog => '../lib/perl5db/t/filename-line-breakpoint'
719        }
720    );
721
722    $wrapper->output_like(qr/
723        ^Var=Bar$
724            .*
725        ^In\ MyModule\.$
726            .*
727        ^In\ Main\ File\.$
728            .*
729        /msx,
730        "Can set breakpoint in a line in the middle of the file.");
731}
732
733# Testing that we can set a breakpoint
734{
735    my $wrapper = DebugWrap->new(
736        {
737            prog => '../lib/perl5db/t/breakpoint-bug',
738            cmds =>
739            [
740                'b 6',
741                'c',
742                q/do { use IO::Handle; STDOUT->autoflush(1); print "X={$x}\n"; }/,
743                'c',
744                'q',
745            ],
746        },
747    );
748
749    $wrapper->output_like(
750        qr/X=\{Two\}/msx,
751        "Can set breakpoint in a line."
752    );
753}
754
755# Testing that we can disable a breakpoint at a numeric line.
756{
757    my $wrapper = DebugWrap->new(
758        {
759            prog =>  '../lib/perl5db/t/disable-breakpoints-1',
760            cmds =>
761            [
762                'b 7',
763                'b 11',
764                'disable 7',
765                'c',
766                q/print "X={$x}\n";/,
767                'c',
768                'q',
769            ],
770        }
771    );
772
773    $wrapper->output_like(qr/X=\{SecondVal\}/ms,
774        "Can set breakpoint in a line.");
775}
776
777# Testing that we can re-enable a breakpoint at a numeric line.
778{
779    my $wrapper = DebugWrap->new(
780        {
781            prog =>  '../lib/perl5db/t/disable-breakpoints-2',
782            cmds =>
783            [
784                'b 8',
785                'b 24',
786                'disable 24',
787                'c',
788                'enable 24',
789                'c',
790                q/print "X={$x}\n";/,
791                'c',
792                'q',
793            ],
794        },
795    );
796
797    $wrapper->output_like(
798        qr/
799        X=\{SecondValOneHundred\}
800        /msx,
801        "Can set breakpoint in a line."
802    );
803}
804# clean up.
805
806# Disable and enable for breakpoints on outer files.
807{
808    my $wrapper = DebugWrap->new(
809        {
810            cmds =>
811            [
812                'b 10',
813                'b ../lib/perl5db/t/EnableModule.pm:14',
814                'disable ../lib/perl5db/t/EnableModule.pm:14',
815                'c',
816                'enable ../lib/perl5db/t/EnableModule.pm:14',
817                'c',
818                q/print "X={$x}\n";/,
819                'c',
820                'q',
821            ],
822            prog =>  '../lib/perl5db/t/disable-breakpoints-3',
823            include_t => 1,
824        }
825    );
826
827    $wrapper->output_like(qr/
828        X=\{SecondValTwoHundred\}
829        /msx,
830        "Can set breakpoint in a line.");
831}
832
833# Testing that the prompt with the information appears.
834{
835    my $wrapper = DebugWrap->new(
836        {
837            cmds => ['q'],
838            prog => '../lib/perl5db/t/disable-breakpoints-1',
839        }
840    );
841
842    $wrapper->contents_like(qr/
843        ^main::\([^\)]*\bdisable-breakpoints-1:2\):\n
844        2:\s+my\ \$x\ =\ "One";\n
845        /msx,
846        "Prompt should display the first line of code.");
847}
848
849# Testing that R (restart) and "B *" work.
850{
851    my $wrapper = DebugWrap->new(
852        {
853            cmds =>
854            [
855                'b 13',
856                'c',
857                'B *',
858                'b 9',
859                'R',
860                'c',
861                q/print "X={$x};dummy={$dummy}\n";/,
862                'q',
863            ],
864            prog =>  '../lib/perl5db/t/disable-breakpoints-1',
865        }
866    );
867
868    $wrapper->output_like(qr/
869        X=\{FirstVal\};dummy=\{1\}
870        /msx,
871        "Restart and delete all breakpoints work properly.");
872}
873
874{
875    my $wrapper = DebugWrap->new(
876        {
877            cmds =>
878            [
879                'c 15',
880                q/print "X={$x}\n";/,
881                'c',
882                'q',
883            ],
884            prog =>  '../lib/perl5db/t/disable-breakpoints-1',
885        }
886    );
887
888    $wrapper->output_like(qr/
889        X=\{ThirdVal\}
890        /msx,
891        "'c line_num' is working properly.");
892}
893
894{
895    my $wrapper = DebugWrap->new(
896        {
897            cmds =>
898            [
899                'n',
900                'n',
901                'b . $exp > 200',
902                'c',
903                q/print "Exp={$exp}\n";/,
904                'q',
905            ],
906            prog => '../lib/perl5db/t/break-on-dot',
907        }
908    );
909
910    $wrapper->output_like(qr/
911        Exp=\{256\}
912        /msx,
913        "'b .' is working correctly.");
914}
915
916# Testing that the prompt with the information appears inside a subroutine call.
917# See https://rt.perl.org/rt3/Ticket/Display.html?id=104820
918{
919    my $wrapper = DebugWrap->new(
920        {
921            cmds =>
922            [
923                'c back',
924                'q',
925            ],
926            prog => '../lib/perl5db/t/with-subroutine',
927        }
928    );
929
930    $wrapper->contents_like(
931        qr/
932        ^main::back\([^\)\n]*\bwith-subroutine:15\):[\ \t]*\n
933        ^15:\s*print\ "hello\ back\\n";
934        /msx,
935        "Prompt should display the line of code inside a subroutine.");
936}
937
938# Checking that the p command works.
939{
940    my $wrapper = DebugWrap->new(
941        {
942            cmds =>
943            [
944                'p "<<<" . (4*6) . ">>>"',
945                'q',
946            ],
947            prog => '../lib/perl5db/t/with-subroutine',
948        }
949    );
950
951    $wrapper->contents_like(
952        qr/<<<24>>>/,
953        "p command works.");
954}
955
956# Tests for x.
957{
958    my $wrapper = DebugWrap->new(
959        {
960            cmds =>
961            [
962                q/x {500 => 600}/,
963                'q',
964            ],
965            prog => '../lib/perl5db/t/with-subroutine',
966        }
967    );
968
969    $wrapper->contents_like(
970        # qr/^0\s+HASH\([^\)]+\)\n\s+500 => 600\n/,
971        qr/^0\s+HASH\([^\)]+\)\n\s+500 => 600\n/ms,
972        "x command test."
973    );
974}
975
976# Tests for x with @_
977{
978    my $wrapper = DebugWrap->new(
979        {
980            cmds =>
981            [
982                'b 10',
983                'c',
984                'x @_',
985                'q',
986            ],
987            prog => '../lib/perl5db/t/test-passing-at-underscore-to-x-etc',
988        }
989    );
990
991    $wrapper->contents_like(
992        # qr/^0\s+HASH\([^\)]+\)\n\s+500 => 600\n/,
993        qr/Arg1.*?Capsula.*GreekHumor.*Socrates/ms,
994        q/x command test with '@_'./,
995    );
996}
997
998# Tests for mutating @_
999{
1000    my $wrapper = DebugWrap->new(
1001        {
1002            cmds =>
1003            [
1004                'b 10',
1005                'c',
1006                'shift(@_)',
1007                'print "\n\n\n(((" . join(",", @_) . ")))\n\n\n"',
1008                'q',
1009            ],
1010            prog => '../lib/perl5db/t/test-passing-at-underscore-to-x-etc',
1011        }
1012    );
1013
1014    $wrapper->output_like(
1015        qr/^\(\(\(Capsula,GreekHumor,Socrates\)\)\)$/ms,
1016        q/Mutating '@_'./,
1017    );
1018}
1019
1020# Tests for x with AutoTrace=1.
1021{
1022    my $wrapper = DebugWrap->new(
1023        {
1024            cmds =>
1025            [
1026                'n',
1027                'o AutoTrace=1',
1028                # So it may fail.
1029                q/x "failure"/,
1030                q/x \$x/,
1031                'q',
1032            ],
1033            prog => '../lib/perl5db/t/with-subroutine',
1034        }
1035    );
1036
1037    $wrapper->contents_like(
1038        # qr/^0\s+HASH\([^\)]+\)\n\s+500 => 600\n/,
1039        qr/^0\s+SCALAR\([^\)]+\)\n\s+-> 'hello world'\n/ms,
1040        "x after AutoTrace=1 command is working."
1041    );
1042}
1043
1044# Tests for "T" (stack trace).
1045{
1046    my $prog_fn = '../lib/perl5db/t/rt-104168';
1047    my $wrapper = DebugWrap->new(
1048        {
1049            prog => $prog_fn,
1050            cmds =>
1051            [
1052                'c baz',
1053                'T',
1054                'q',
1055            ],
1056        }
1057    );
1058    my $re_text = join('',
1059        map {
1060        sprintf(
1061            "%s = %s\\(\\) called from file " .
1062            "'" . quotemeta($prog_fn) . "' line %s\\n",
1063            (map { quotemeta($_) } @$_)
1064            )
1065        }
1066        (
1067            ['.', 'main::baz', 14,],
1068            ['.', 'main::bar', 9,],
1069            ['.', 'main::foo', 6],
1070        )
1071    );
1072    $wrapper->contents_like(
1073        # qr/^0\s+HASH\([^\)]+\)\n\s+500 => 600\n/,
1074        qr/^$re_text/ms,
1075        "T command test."
1076    );
1077}
1078
1079# Test for s.
1080{
1081    my $wrapper = DebugWrap->new(
1082        {
1083            cmds =>
1084            [
1085                'b 9',
1086                'c',
1087                's',
1088                q/print "X={$x};dummy={$dummy}\n";/,
1089                'q',
1090            ],
1091            prog => '../lib/perl5db/t/disable-breakpoints-1'
1092        }
1093    );
1094
1095    $wrapper->output_like(qr/
1096        X=\{SecondVal\};dummy=\{1\}
1097        /msx,
1098        'test for s - single step',
1099    );
1100}
1101
1102{
1103    my $wrapper = DebugWrap->new(
1104        {
1105            cmds =>
1106            [
1107                'n',
1108                'n',
1109                'b . $exp > 200',
1110                'c',
1111                q/print "Exp={$exp}\n";/,
1112                'q',
1113            ],
1114            prog => '../lib/perl5db/t/break-on-dot'
1115        }
1116    );
1117
1118    $wrapper->output_like(qr/
1119        Exp=\{256\}
1120        /msx,
1121        "'b .' is working correctly.");
1122}
1123
1124{
1125    my $prog_fn = '../lib/perl5db/t/rt-104168';
1126    my $wrapper = DebugWrap->new(
1127        {
1128            cmds =>
1129            [
1130                's',
1131                'q',
1132            ],
1133            prog => $prog_fn,
1134        }
1135    );
1136
1137    $wrapper->contents_like(
1138        qr/
1139        ^main::foo\([^\)\n]*\brt-104168:9\):[\ \t]*\n
1140        ^9:\s*bar\(\);
1141        /msx,
1142        'Test for the s command.',
1143    );
1144}
1145
1146{
1147    my $wrapper = DebugWrap->new(
1148        {
1149            cmds =>
1150            [
1151                's uncalled_subroutine()',
1152                'c',
1153                'q',
1154            ],
1155
1156            prog => '../lib/perl5db/t/uncalled-subroutine'}
1157    );
1158
1159    $wrapper->output_like(
1160        qr/<1,2,3,4,5>\n/,
1161        'uncalled_subroutine was called after s EXPR()',
1162        );
1163}
1164
1165{
1166    my $wrapper = DebugWrap->new(
1167        {
1168            cmds =>
1169            [
1170                'n uncalled_subroutine()',
1171                'c',
1172                'q',
1173            ],
1174            prog => '../lib/perl5db/t/uncalled-subroutine',
1175        }
1176    );
1177
1178    $wrapper->output_like(
1179        qr/<1,2,3,4,5>\n/,
1180        'uncalled_subroutine was called after n EXPR()',
1181        );
1182}
1183
1184{
1185    my $wrapper = DebugWrap->new(
1186        {
1187            cmds =>
1188            [
1189                'b fact',
1190                'c',
1191                'c',
1192                'c',
1193                'n',
1194                'print "<$n>"',
1195                'q',
1196            ],
1197            prog => '../lib/perl5db/t/fact',
1198        }
1199    );
1200
1201    $wrapper->output_like(
1202        qr/<3>/,
1203        'b subroutine works fine',
1204    );
1205}
1206
1207# Test for n with lvalue subs
1208DebugWrap->new({
1209    cmds =>
1210    [
1211        'n', 'print "<$x>\n"',
1212        'n', 'print "<$x>\n"',
1213        'q',
1214    ],
1215    prog => '../lib/perl5db/t/lsub-n',
1216})->output_like(
1217    qr/<1>\n<11>\n/,
1218    'n steps over lvalue subs',
1219);
1220
1221# Test for 'M' (module list).
1222{
1223    my $wrapper = DebugWrap->new(
1224        {
1225            cmds =>
1226            [
1227                'M',
1228                'q',
1229            ],
1230            prog => '../lib/perl5db/t/load-modules'
1231        }
1232    );
1233
1234    $wrapper->contents_like(
1235        qr[Scalar/Util\.pm],
1236        'M (module list) works fine',
1237    );
1238}
1239
1240{
1241    my $wrapper = DebugWrap->new(
1242        {
1243            cmds =>
1244            [
1245                'b 14',
1246                'c',
1247                '$flag = 1;',
1248                'r',
1249                'print "Var=$var\n";',
1250                'q',
1251            ],
1252            prog => '../lib/perl5db/t/test-r-statement',
1253        }
1254    );
1255
1256    $wrapper->output_like(
1257        qr/
1258            ^Foo$
1259                .*?
1260            ^Bar$
1261                .*?
1262            ^Var=Test$
1263        /msx,
1264        'r statement is working properly.',
1265    );
1266}
1267
1268{
1269    my $wrapper = DebugWrap->new(
1270        {
1271            cmds =>
1272            [
1273                'l',
1274                'q',
1275            ],
1276            prog => '../lib/perl5db/t/test-l-statement-1',
1277        }
1278    );
1279
1280    $wrapper->contents_like(
1281        qr/
1282            ^1==>\s+\$x\ =\ 1;\n
1283            2:\s+print\ "1\\n";\n
1284            3\s*\n
1285            4:\s+\$x\ =\ 2;\n
1286            5:\s+print\ "2\\n";\n
1287        /msx,
1288        'l statement is working properly (test No. 1).',
1289    );
1290}
1291
1292{
1293    my $wrapper = DebugWrap->new(
1294        {
1295            cmds =>
1296            [
1297                'l',
1298                q/# After l 1/,
1299                'l',
1300                q/# After l 2/,
1301                '-',
1302                q/# After -/,
1303                'q',
1304            ],
1305            prog => '../lib/perl5db/t/test-l-statement-1',
1306        }
1307    );
1308
1309    my $first_l_out = qr/
1310        1==>\s+\$x\ =\ 1;\n
1311        2:\s+print\ "1\\n";\n
1312        3\s*\n
1313        4:\s+\$x\ =\ 2;\n
1314        5:\s+print\ "2\\n";\n
1315        6\s*\n
1316        7:\s+\$x\ =\ 3;\n
1317        8:\s+print\ "3\\n";\n
1318        9\s*\n
1319        10:\s+\$x\ =\ 4;\n
1320    /msx;
1321
1322    my $second_l_out = qr/
1323        11:\s+print\ "4\\n";\n
1324        12\s*\n
1325        13:\s+\$x\ =\ 5;\n
1326        14:\s+print\ "5\\n";\n
1327        15\s*\n
1328        16:\s+\$x\ =\ 6;\n
1329        17:\s+print\ "6\\n";\n
1330        18\s*\n
1331        19:\s+\$x\ =\ 7;\n
1332        20:\s+print\ "7\\n";\n
1333    /msx;
1334    $wrapper->contents_like(
1335        qr/
1336            ^$first_l_out
1337            [^\n]*?DB<\d+>\ \#\ After\ l\ 1\n
1338            [\ \t]*\n
1339            [^\n]*?DB<\d+>\ l\s*\n
1340            $second_l_out
1341            [^\n]*?DB<\d+>\ \#\ After\ l\ 2\n
1342            [\ \t]*\n
1343            [^\n]*?DB<\d+>\ -\s*\n
1344            $first_l_out
1345            [^\n]*?DB<\d+>\ \#\ After\ -\n
1346        /msx,
1347        'l followed by l and then followed by -',
1348    );
1349}
1350
1351{
1352    my $wrapper = DebugWrap->new(
1353        {
1354            cmds =>
1355            [
1356                'v',
1357                'q',
1358            ],
1359            prog => '../lib/perl5db/t/test-l-statement-1',
1360        }
1361       );
1362    $wrapper->contents_like(
1363        qr/
1364          1==>\s+\$x\ =\ 1;\n
1365          2:\s+print\ "1\\n";\n
1366          3\s+\n
1367          4:\s+\$x\ =\ 2;\n
1368          5:\s+print\ "2\\n";\n
1369          6\s*\n
1370          7:\s+\$x\ =\ 3;\n
1371          /msx,
1372        "test plain v"
1373        );
1374}
1375
1376{
1377    my $wrapper = DebugWrap->new(
1378        {
1379            cmds =>
1380            [
1381                'v 10',
1382                'q',
1383            ],
1384            prog => '../lib/perl5db/t/test-l-statement-1',
1385        }
1386       );
1387
1388    $wrapper->contents_like(
1389        qr/
1390          7:\s+\$x\ =\ 3;\n
1391          8:\s+print\ "3\\n";\n
1392          9\s*\n
1393          10:\s+\$x\ =\ 4;\n
1394          11:\s+print\ "4\\n";\n
1395          12\s*\n
1396          13:\s+\$x\ =\ 5;\n
1397          14:\s+print\ "5\\n";\n
1398          15\s*\n
1399          16:\s+\$x\ =\ 6;\n
1400          /msx,
1401        "test v with line"
1402        );
1403}
1404
1405{
1406    my $wrapper = DebugWrap->new(
1407        {
1408            cmds =>
1409            [
1410                'l fact',
1411                'q',
1412            ],
1413            prog => '../lib/perl5db/t/test-l-statement-2',
1414        }
1415    );
1416
1417    my $first_l_out = qr/
1418        6\s+sub\ fact\ \{\n
1419        7:\s+my\ \$n\ =\ shift;\n
1420        8:\s+if\ \(\$n\ >\ 1\)\ \{\n
1421        9:\s+return\ \$n\ \*\ fact\(\$n\ -\ 1\);
1422    /msx;
1423
1424    $wrapper->contents_like(
1425        qr/
1426            DB<1>\s+l\ fact\n
1427            $first_l_out
1428        /msx,
1429        'l subroutine_name',
1430    );
1431}
1432
1433{
1434    my $wrapper = DebugWrap->new(
1435        {
1436            cmds =>
1437            [
1438                'b fact',
1439                'c',
1440                # Repeat several times to avoid @typeahead problems.
1441                '.',
1442                '.',
1443                '.',
1444                '.',
1445                'q',
1446            ],
1447            prog => '../lib/perl5db/t/test-l-statement-2',
1448        }
1449    );
1450
1451    my $line_out = qr /
1452        ^main::fact\([^\n]*?:7\):\n
1453        ^7:\s+my\ \$n\ =\ shift;\n
1454    /msx;
1455
1456    $wrapper->contents_like(
1457        qr/
1458            $line_out
1459            auto\(-\d+\)\s+DB<\d+>\s+\.\n
1460            $line_out
1461        /msx,
1462        'Test the "." command',
1463    );
1464}
1465
1466# Testing that the f command works.
1467{
1468    my $wrapper = DebugWrap->new(
1469        {
1470            cmds =>
1471            [
1472                'f ../lib/perl5db/t/MyModule.pm',
1473                'b 12',
1474                'c',
1475                q/do { use IO::Handle; STDOUT->autoflush(1); print "Var=$var\n"; }/,
1476                'c',
1477                'q',
1478            ],
1479            include_t => 1,
1480            prog => '../lib/perl5db/t/filename-line-breakpoint'
1481        }
1482    );
1483
1484    $wrapper->output_like(qr/
1485        ^Var=Bar$
1486            .*
1487        ^In\ MyModule\.$
1488            .*
1489        ^In\ Main\ File\.$
1490            .*
1491        /msx,
1492        "f command is working.",
1493    );
1494}
1495
1496# We broke the /pattern/ command because apparently the CORE::eval-s inside
1497# lib/perl5db.pl cannot handle lexical variable properly. So we now fix this
1498# bug.
1499#
1500# TODO :
1501#
1502# 1. Go over the rest of the "eval"s in lib/perl5db.t and see if they cause
1503# problems.
1504{
1505    my $wrapper = DebugWrap->new(
1506        {
1507            cmds =>
1508            [
1509                '/for/',
1510                'q',
1511            ],
1512            prog => '../lib/perl5db/t/eval-line-bug',
1513        }
1514    );
1515
1516    $wrapper->contents_like(
1517        qr/12: \s* for\ my\ \$q\ \(1\ \.\.\ 10\)\ \{/msx,
1518        "/pat/ command is working and found a match.",
1519    );
1520}
1521
1522{
1523    my $wrapper = DebugWrap->new(
1524        {
1525            cmds =>
1526            [
1527                'b 22',
1528                'c',
1529                '?for?',
1530                'q',
1531            ],
1532            prog => '../lib/perl5db/t/eval-line-bug',
1533        }
1534    );
1535
1536    $wrapper->contents_like(
1537        qr/12: \s* for\ my\ \$q\ \(1\ \.\.\ 10\)\ \{/msx,
1538        "?pat? command is working and found a match.",
1539    );
1540}
1541
1542# Test the L command.
1543{
1544    my $wrapper = DebugWrap->new(
1545        {
1546            cmds =>
1547            [
1548                'b 6',
1549                'b 13 ($q == 5)',
1550                'L',
1551                'q',
1552            ],
1553            prog => '../lib/perl5db/t/eval-line-bug',
1554        }
1555    );
1556
1557    $wrapper->contents_like(
1558        qr#
1559        ^\S*?eval-line-bug:\n
1560        \s*6:\s*my\ \$i\ =\ 5;\n
1561        \s*break\ if\ \(1\)\n
1562        \s*13:\s*\$i\ \+=\ \$q;\n
1563        \s*break\ if\ \(\(\$q\ ==\ 5\)\)\n
1564        #msx,
1565        "L command is listing breakpoints",
1566    );
1567}
1568
1569# Test the L command for watch expressions.
1570{
1571    my $wrapper = DebugWrap->new(
1572        {
1573            cmds =>
1574            [
1575                'w (5+6)',
1576                'L',
1577                'q',
1578            ],
1579            prog => '../lib/perl5db/t/eval-line-bug',
1580        }
1581    );
1582
1583    $wrapper->contents_like(
1584        qr#
1585        ^Watch-expressions:\n
1586        \s*\(5\+6\)\n
1587        #msx,
1588        "L command is listing watch expressions",
1589    );
1590}
1591
1592{
1593    my $wrapper = DebugWrap->new(
1594        {
1595            cmds =>
1596            [
1597                'w (5+6)',
1598                'w (11*23)',
1599                'W (5+6)',
1600                'L',
1601                'q',
1602            ],
1603            prog => '../lib/perl5db/t/eval-line-bug',
1604        }
1605    );
1606
1607    $wrapper->contents_like(
1608        qr#
1609        ^Watch-expressions:\n
1610        \s*\(11\*23\)\n
1611        ^auto\(
1612        #msx,
1613        "L command is not listing deleted watch expressions",
1614    );
1615}
1616
1617# Test the L command.
1618{
1619    my $wrapper = DebugWrap->new(
1620        {
1621            cmds =>
1622            [
1623                'b 6',
1624                'a 13 print $i',
1625                'L',
1626                'q',
1627            ],
1628            prog => '../lib/perl5db/t/eval-line-bug',
1629        }
1630    );
1631
1632    $wrapper->contents_like(
1633        qr#
1634        ^\S*?eval-line-bug:\n
1635        \s*6:\s*my\ \$i\ =\ 5;\n
1636        \s*break\ if\ \(1\)\n
1637        \s*13:\s*\$i\ \+=\ \$q;\n
1638        \s*action:\s+print\ \$i\n
1639        #msx,
1640        "L command is listing actions and breakpoints",
1641    );
1642}
1643
1644{
1645    my $wrapper = DebugWrap->new(
1646        {
1647            cmds =>
1648            [
1649                'S',
1650                'q',
1651            ],
1652            prog =>  '../lib/perl5db/t/rt-104168',
1653        }
1654    );
1655
1656    $wrapper->contents_like(
1657        qr#
1658        ^main::bar\n
1659        main::baz\n
1660        main::foo\n
1661        #msx,
1662        "S command - 1",
1663    );
1664}
1665
1666{
1667    my $wrapper = DebugWrap->new(
1668        {
1669            cmds =>
1670            [
1671                'S ^main::ba',
1672                'q',
1673            ],
1674            prog =>  '../lib/perl5db/t/rt-104168',
1675        }
1676    );
1677
1678    $wrapper->contents_like(
1679        qr#
1680        ^main::bar\n
1681        main::baz\n
1682        auto\(
1683        #msx,
1684        "S command with regex",
1685    );
1686}
1687
1688{
1689    my $wrapper = DebugWrap->new(
1690        {
1691            cmds =>
1692            [
1693                'S !^main::ba',
1694                'q',
1695            ],
1696            prog =>  '../lib/perl5db/t/rt-104168',
1697        }
1698    );
1699
1700    $wrapper->contents_unlike(
1701        qr#
1702        ^main::ba
1703        #msx,
1704        "S command with negative regex",
1705    );
1706
1707    $wrapper->contents_like(
1708        qr#
1709        ^main::foo\n
1710        #msx,
1711        "S command with negative regex - what it still matches",
1712    );
1713}
1714
1715# Test the 'a' command.
1716{
1717    my $wrapper = DebugWrap->new(
1718        {
1719            cmds =>
1720            [
1721                'a 13 print "\nVar<Q>=$q\n"',
1722                'c',
1723                'q',
1724            ],
1725            prog => '../lib/perl5db/t/eval-line-bug',
1726        }
1727    );
1728
1729    my $nl = $^O eq 'VMS' ? "" : "\\\n";
1730    $wrapper->output_like(qr#
1731        \nVar<Q>=1$nl
1732        \nVar<Q>=2$nl
1733        \nVar<Q>=3
1734        #msx,
1735        "a command is working",
1736    );
1737}
1738
1739# Test the 'a' command with no line number.
1740{
1741    my $wrapper = DebugWrap->new(
1742        {
1743            cmds =>
1744            [
1745                'n',
1746                q/a print "Hello " . (3 * 4) . "\n";/,
1747                'c',
1748                'q',
1749            ],
1750            prog => '../lib/perl5db/t/test-a-statement-1',
1751        }
1752    );
1753
1754    $wrapper->output_like(qr#
1755        (?:^Hello\ 12\n.*?){4}
1756        #msx,
1757        "a command with no line number is working",
1758    );
1759}
1760
1761# Test the 'A' command
1762{
1763    my $wrapper = DebugWrap->new(
1764        {
1765            cmds =>
1766            [
1767                'a 13 print "\nVar<Q>=$q\n"',
1768                'A 13',
1769                'c',
1770                'q',
1771            ],
1772            prog => '../lib/perl5db/t/eval-line-bug',
1773        }
1774    );
1775
1776    $wrapper->output_like(
1777        qr#\A\z#msx, # The empty string.
1778        "A command (for removing actions) is working",
1779    );
1780}
1781
1782# Test the 'A *' command
1783{
1784    my $wrapper = DebugWrap->new(
1785        {
1786            cmds =>
1787            [
1788                'a 6 print "\nFail!\n"',
1789                'a 13 print "\nVar<Q>=$q\n"',
1790                'A *',
1791                'c',
1792                'q',
1793            ],
1794            prog => '../lib/perl5db/t/eval-line-bug',
1795        }
1796    );
1797
1798    $wrapper->output_like(
1799        qr#\A\z#msx, # The empty string.
1800        "'A *' command (for removing all actions) is working",
1801    );
1802}
1803
1804{
1805    my $wrapper = DebugWrap->new(
1806        {
1807            cmds =>
1808            [
1809                'n',
1810                'w $foo',
1811                'c',
1812                'print "\nIDX=<$idx>\n"',
1813                'q',
1814            ],
1815            prog => '../lib/perl5db/t/test-w-statement-1',
1816        }
1817    );
1818
1819
1820    $wrapper->contents_like(qr#
1821        \$foo\ changed:\n
1822        \s+old\ value:\s+'1'\n
1823        \s+new\ value:\s+'2'\n
1824        #msx,
1825        'w command - watchpoint changed',
1826    );
1827    $wrapper->output_like(qr#
1828        \nIDX=<20>\n
1829        #msx,
1830        "w command - correct output from IDX",
1831    );
1832}
1833
1834{
1835    my $wrapper = DebugWrap->new(
1836        {
1837            cmds =>
1838            [
1839                'n',
1840                'w $foo',
1841                'W $foo',
1842                'c',
1843                'print "\nIDX=<$idx>\n"',
1844                'q',
1845            ],
1846            prog => '../lib/perl5db/t/test-w-statement-1',
1847        }
1848    );
1849
1850    $wrapper->contents_unlike(qr#
1851        \$foo\ changed:
1852        #msx,
1853        'W command - watchpoint was deleted',
1854    );
1855
1856    $wrapper->output_like(qr#
1857        \nIDX=<>\n
1858        #msx,
1859        "W command - stopped at end.",
1860    );
1861}
1862
1863# Test the W * command.
1864{
1865    my $wrapper = DebugWrap->new(
1866        {
1867            cmds =>
1868            [
1869                'n',
1870                'w $foo',
1871                'w ($foo*$foo)',
1872                'W *',
1873                'c',
1874                'print "\nIDX=<$idx>\n"',
1875                'q',
1876            ],
1877            prog => '../lib/perl5db/t/test-w-statement-1',
1878        }
1879    );
1880
1881    $wrapper->contents_unlike(qr#
1882        \$foo\ changed:
1883        #msx,
1884        '"W *" command - watchpoint was deleted',
1885    );
1886
1887    $wrapper->output_like(qr#
1888        \nIDX=<>\n
1889        #msx,
1890        '"W *" command - stopped at end.',
1891    );
1892}
1893
1894# Test the 'o' command (without further arguments).
1895{
1896    my $wrapper = DebugWrap->new(
1897        {
1898            cmds =>
1899            [
1900                'o',
1901                'q',
1902            ],
1903            prog => '../lib/perl5db/t/test-w-statement-1',
1904        }
1905    );
1906
1907    $wrapper->contents_like(qr#
1908        ^\s*warnLevel\ =\ '1'\n
1909        #msx,
1910        q#"o" command (without arguments) displays warnLevel#,
1911    );
1912
1913    $wrapper->contents_like(qr#
1914        ^\s*signalLevel\ =\ '1'\n
1915        #msx,
1916        q#"o" command (without arguments) displays signalLevel#,
1917    );
1918
1919    $wrapper->contents_like(qr#
1920        ^\s*dieLevel\ =\ '1'\n
1921        #msx,
1922        q#"o" command (without arguments) displays dieLevel#,
1923    );
1924
1925    $wrapper->contents_like(qr#
1926        ^\s*hashDepth\ =\ 'N/A'\n
1927        #msx,
1928        q#"o" command (without arguments) displays hashDepth#,
1929    );
1930}
1931
1932# Test the 'o' query command.
1933{
1934    my $wrapper = DebugWrap->new(
1935        {
1936            cmds =>
1937            [
1938                'o hashDepth? signalLevel?',
1939                'q',
1940            ],
1941            prog => '../lib/perl5db/t/test-w-statement-1',
1942        }
1943    );
1944
1945    $wrapper->contents_unlike(qr#warnLevel#,
1946        q#"o" query command does not display warnLevel#,
1947    );
1948
1949    $wrapper->contents_like(qr#
1950        ^\s*signalLevel\ =\ '1'\n
1951        #msx,
1952        q#"o" query command displays signalLevel#,
1953    );
1954
1955    $wrapper->contents_unlike(qr#dieLevel#,
1956        q#"o" query command does not display dieLevel#,
1957    );
1958
1959    $wrapper->contents_like(qr#
1960        ^\s*hashDepth\ =\ 'N/A'\n
1961        #msx,
1962        q#"o" query command displays hashDepth#,
1963    );
1964}
1965
1966# Test the 'o' set command.
1967{
1968    my $wrapper = DebugWrap->new(
1969        {
1970            cmds =>
1971            [
1972                'o signalLevel=0',
1973                'o',
1974                'q',
1975            ],
1976            prog => '../lib/perl5db/t/test-w-statement-1',
1977        }
1978    );
1979
1980    $wrapper->contents_like(qr/
1981        ^\s*(signalLevel\ =\ '0'\n)
1982        .*?
1983        ^\s*\1
1984        /msx,
1985        q#o set command works#,
1986    );
1987
1988    $wrapper->contents_like(qr#
1989        ^\s*hashDepth\ =\ 'N/A'\n
1990        #msx,
1991        q#o set command - hashDepth#,
1992    );
1993}
1994
1995# Test the '<' and "< ?" commands.
1996{
1997    my $wrapper = DebugWrap->new(
1998        {
1999            cmds =>
2000            [
2001                q/< print "\nX=<$x>\n"/,
2002                q/b 7/,
2003                q/< ?/,
2004                'c',
2005                'q',
2006            ],
2007            prog => '../lib/perl5db/t/disable-breakpoints-1',
2008        }
2009    );
2010
2011    $wrapper->contents_like(qr/
2012        ^pre-perl\ commands:\n
2013        \s*<\ --\ print\ "\\nX=<\$x>\\n"\n
2014        /msx,
2015        q#Test < and < ? commands - contents.#,
2016    );
2017
2018    $wrapper->output_like(qr#
2019        ^X=<FirstVal>\n
2020        #msx,
2021        q#Test < and < ? commands - output.#,
2022    );
2023}
2024
2025# Test the '< *' command.
2026{
2027    my $wrapper = DebugWrap->new(
2028        {
2029            cmds =>
2030            [
2031                q/< print "\nX=<$x>\n"/,
2032                q/b 7/,
2033                q/< */,
2034                'c',
2035                'q',
2036            ],
2037            prog => '../lib/perl5db/t/disable-breakpoints-1',
2038        }
2039    );
2040
2041    $wrapper->output_unlike(qr/FirstVal/,
2042        q#Test the '< *' command.#,
2043    );
2044}
2045
2046# Test the '>' and "> ?" commands.
2047{
2048    my $wrapper = DebugWrap->new(
2049        {
2050            cmds =>
2051            [
2052                q/$::foo = 500;/,
2053                q/> print "\nFOO=<$::foo>\n"/,
2054                q/b 7/,
2055                q/> ?/,
2056                'c',
2057                'q',
2058            ],
2059            prog => '../lib/perl5db/t/disable-breakpoints-1',
2060        }
2061    );
2062
2063    $wrapper->contents_like(qr/
2064        ^post-perl\ commands:\n
2065        \s*>\ --\ print\ "\\nFOO=<\$::foo>\\n"\n
2066        /msx,
2067        q#Test > and > ? commands - contents.#,
2068    );
2069
2070    $wrapper->output_like(qr#
2071        ^FOO=<500>\n
2072        #msx,
2073        q#Test > and > ? commands - output.#,
2074    );
2075}
2076
2077# Test the '> *' command.
2078{
2079    my $wrapper = DebugWrap->new(
2080        {
2081            cmds =>
2082            [
2083                q/> print "\nFOO=<$::foo>\n"/,
2084                q/b 7/,
2085                q/> */,
2086                'c',
2087                'q',
2088            ],
2089            prog => '../lib/perl5db/t/disable-breakpoints-1',
2090        }
2091    );
2092
2093    $wrapper->output_unlike(qr/FOO=/,
2094        q#Test the '> *' command.#,
2095    );
2096}
2097
2098# Test the < and > commands together
2099{
2100    my $wrapper = DebugWrap->new(
2101        {
2102            cmds =>
2103            [
2104                q/$::lorem = 0;/,
2105                q/< $::lorem += 10;/,
2106                q/> print "\nLOREM=<$::lorem>\n"/,
2107                q/b 7/,
2108                q/b 5/,
2109                'c',
2110                'c',
2111                'q',
2112            ],
2113            prog => '../lib/perl5db/t/disable-breakpoints-1',
2114        }
2115    );
2116
2117    $wrapper->output_like(qr#
2118        ^LOREM=<10>\n
2119        #msx,
2120        q#Test < and > commands. #,
2121    );
2122}
2123
2124# Test the { ? and { [command] commands.
2125{
2126    my $wrapper = DebugWrap->new(
2127        {
2128            cmds =>
2129            [
2130                '{ ?',
2131                '{ l',
2132                '{ ?',
2133                q/b 5/,
2134                q/c/,
2135                q/q/,
2136            ],
2137            prog => '../lib/perl5db/t/disable-breakpoints-1',
2138        }
2139    );
2140
2141    $wrapper->contents_like(qr#
2142        ^No\ pre-debugger\ actions\.\n
2143        .*?
2144        ^pre-debugger\ commands:\n
2145        \s+\{\ --\ l\n
2146        .*?
2147        ^5==>b\s+\$x\ =\ "FirstVal";\n
2148        6\s*\n
2149        7:\s+\$dummy\+\+;\n
2150        8\s*\n
2151        9:\s+\$x\ =\ "SecondVal";\n
2152
2153        #msx,
2154        'Test the pre-prompt debugger commands',
2155    );
2156}
2157
2158# Test the { * command.
2159{
2160    my $wrapper = DebugWrap->new(
2161        {
2162            cmds =>
2163            [
2164                '{ q',
2165                '{ *',
2166                q/b 5/,
2167                q/c/,
2168                q/print (("One" x 5), "\n");/,
2169                q/q/,
2170            ],
2171            prog => '../lib/perl5db/t/disable-breakpoints-1',
2172        }
2173    );
2174
2175    $wrapper->contents_like(qr#
2176        ^All\ \{\ actions\ cleared\.\n
2177        #msx,
2178        'Test the { * command',
2179    );
2180
2181    $wrapper->output_like(qr/OneOneOneOneOne/,
2182        '{ * test - output is OK.',
2183    );
2184}
2185
2186# Test the ! command.
2187{
2188    my $wrapper = DebugWrap->new(
2189        {
2190            cmds =>
2191            [
2192                'l 3-5',
2193                '!',
2194                'q',
2195            ],
2196            prog => '../lib/perl5db/t/disable-breakpoints-1',
2197        }
2198    );
2199
2200    $wrapper->contents_like(qr#
2201        (^3:\s+my\ \$dummy\ =\ 0;\n
2202        4\s*\n
2203        5:\s+\$x\ =\ "FirstVal";)\n
2204        .*?
2205        ^l\ 3-5\n
2206        \1
2207        #msx,
2208        'Test the ! command (along with l 3-5)',
2209    );
2210}
2211
2212# Test the ! -number command.
2213{
2214    my $wrapper = DebugWrap->new(
2215        {
2216            cmds =>
2217            [
2218                'l 3-5',
2219                'l 2',
2220                '! -1',
2221                'q',
2222            ],
2223            prog => '../lib/perl5db/t/disable-breakpoints-1',
2224        }
2225    );
2226
2227    $wrapper->contents_like(qr#
2228        (^3:\s+my\ \$dummy\ =\ 0;\n
2229        4\s*\n
2230        5:\s+\$x\ =\ "FirstVal";)\n
2231        .*?
2232        ^2==\>\s+my\ \$x\ =\ "One";\n
2233        .*?
2234        ^l\ 3-5\n
2235        \1
2236        #msx,
2237        'Test the ! -n command (along with l)',
2238    );
2239}
2240
2241# Test the 'source' command.
2242{
2243    my $wrapper = DebugWrap->new(
2244        {
2245            cmds =>
2246            [
2247                'source ../lib/perl5db/t/source-cmd-test.perldb',
2248                # If we have a 'q' here, then the typeahead will override the
2249                # input, and so it won't be reached - solution:
2250                # put a q inside the .perldb commands.
2251                # ( This may be a bug or a misfeature. )
2252            ],
2253            prog => '../lib/perl5db/t/disable-breakpoints-1',
2254        }
2255    );
2256
2257    $wrapper->contents_like(qr#
2258        ^3:\s+my\ \$dummy\ =\ 0;\n
2259        4\s*\n
2260        5:\s+\$x\ =\ "FirstVal";\n
2261        6\s*\n
2262        7:\s+\$dummy\+\+;\n
2263        8\s*\n
2264        9:\s+\$x\ =\ "SecondVal";\n
2265        10\s*\n
2266        #msx,
2267        'Test the source command (along with l)',
2268    );
2269}
2270
2271# Test the 'source' command being traversed from withing typeahead.
2272{
2273    my $wrapper = DebugWrap->new(
2274        {
2275            cmds =>
2276            [
2277                'source ../lib/perl5db/t/source-cmd-test-no-q.perldb',
2278                'q',
2279            ],
2280            prog => '../lib/perl5db/t/disable-breakpoints-1',
2281        }
2282    );
2283
2284    $wrapper->contents_like(qr#
2285        ^3:\s+my\ \$dummy\ =\ 0;\n
2286        4\s*\n
2287        5:\s+\$x\ =\ "FirstVal";\n
2288        6\s*\n
2289        7:\s+\$dummy\+\+;\n
2290        8\s*\n
2291        9:\s+\$x\ =\ "SecondVal";\n
2292        10\s*\n
2293        #msx,
2294        'Test the source command inside a typeahead',
2295    );
2296}
2297
2298# Test the 'H -number' command.
2299{
2300    my $wrapper = DebugWrap->new(
2301        {
2302            cmds =>
2303            [
2304                'l 1-10',
2305                'l 5-10',
2306                'x "Hello World"',
2307                'l 1-5',
2308                'b 3',
2309                'x (20+4)',
2310                'H -7',
2311                'q',
2312            ],
2313            prog => '../lib/perl5db/t/disable-breakpoints-1',
2314        }
2315    );
2316
2317    $wrapper->contents_like(qr#
2318        ^\d+:\s+H\ -7\n
2319        \d+:\s+x\ \(20\+4\)\n
2320        \d+:\s+b\ 3\n
2321        \d+:\s+l\ 1-5\n
2322        \d+:\s+x\ "Hello\ World"\n
2323        \d+:\s+l\ 5-10\n
2324        \d+:\s+l\ 1-10\n
2325        #msx,
2326        'Test the H -num command',
2327    );
2328}
2329
2330# Add a test for H (without arguments)
2331{
2332    my $wrapper = DebugWrap->new(
2333        {
2334            cmds =>
2335            [
2336                'l 1-10',
2337                'l 5-10',
2338                'x "Hello World"',
2339                'l 1-5',
2340                'b 3',
2341                'x (20+4)',
2342                'H',
2343                'q',
2344            ],
2345            prog => '../lib/perl5db/t/disable-breakpoints-1',
2346        }
2347    );
2348
2349    $wrapper->contents_like(qr#
2350        ^\d+:\s+x\ \(20\+4\)\n
2351        \d+:\s+b\ 3\n
2352        \d+:\s+l\ 1-5\n
2353        \d+:\s+x\ "Hello\ World"\n
2354        \d+:\s+l\ 5-10\n
2355        \d+:\s+l\ 1-10\n
2356        #msx,
2357        'Test the H command (without a number.)',
2358    );
2359}
2360
2361{
2362    my $wrapper = DebugWrap->new(
2363        {
2364            cmds =>
2365            [
2366                '= quit q',
2367                '= foobar l',
2368                '= .hello print "hellox\n"',
2369                '= -goodbye print "goodbyex\n"',
2370                'foobar',
2371                '.hello',
2372                '-goodbye',
2373                'quit',
2374            ],
2375            prog => '../lib/perl5db/t/test-l-statement-1',
2376        }
2377    );
2378
2379    $wrapper->contents_like(
2380        qr/
2381            ^1==>\s+\$x\ =\ 1;\n
2382            2:\s+print\ "1\\n";\n
2383            3\s*\n
2384            4:\s+\$x\ =\ 2;\n
2385            5:\s+print\ "2\\n";\n
2386        /msx,
2387        'Test the = (command alias) command.',
2388       );
2389    $wrapper->output_like(qr/hellox.*goodbyex/xs,
2390                          "check . and - can start alias name");
2391}
2392
2393# Test the m statement.
2394{
2395    my $wrapper = DebugWrap->new(
2396        {
2397            cmds =>
2398            [
2399                'm main',
2400                'q',
2401            ],
2402            prog => '../lib/perl5db/t/disable-breakpoints-1',
2403        }
2404    );
2405
2406    $wrapper->contents_like(qr#
2407        ^via\ UNIVERSAL:\ DOES$
2408        #msx,
2409        "Test m for main - 1",
2410    );
2411
2412    $wrapper->contents_like(qr#
2413        ^via\ UNIVERSAL:\ can$
2414        #msx,
2415        "Test m for main - 2",
2416    );
2417}
2418
2419# Test the m statement.
2420{
2421    my $wrapper = DebugWrap->new(
2422        {
2423            cmds =>
2424            [
2425                'b 41',
2426                'c',
2427                'm $obj',
2428                'q',
2429            ],
2430            prog => '../lib/perl5db/t/test-m-statement-1',
2431        }
2432    );
2433
2434    $wrapper->contents_like(qr#^greet$#ms,
2435        "Test m for obj - 1",
2436    );
2437
2438    $wrapper->contents_like(qr#^via UNIVERSAL: can$#ms,
2439        "Test m for obj - 1",
2440    );
2441}
2442
2443# Test the M command.
2444{
2445    my $wrapper = DebugWrap->new(
2446        {
2447            cmds =>
2448            [
2449                'M',
2450                'q',
2451            ],
2452            prog => '../lib/perl5db/t/test-m-statement-1',
2453        }
2454    );
2455
2456    $wrapper->contents_like(qr#
2457        ^'strict\.pm'\ =>\ '\d+\.\d+\ from
2458        #msx,
2459        "Test M",
2460    );
2461
2462}
2463
2464# Test the recallCommand option.
2465{
2466    my $wrapper = DebugWrap->new(
2467        {
2468            cmds =>
2469            [
2470                'o recallCommand=%',
2471                'l 3-5',
2472                'l 2',
2473                '% -1',
2474                'q',
2475            ],
2476            prog => '../lib/perl5db/t/disable-breakpoints-1',
2477        }
2478    );
2479
2480    $wrapper->contents_like(qr#
2481        (^3:\s+my\ \$dummy\ =\ 0;\n
2482        4\s*\n
2483        5:\s+\$x\ =\ "FirstVal";)\n
2484        .*?
2485        ^2==\>\s+my\ \$x\ =\ "One";\n
2486        .*?
2487        ^l\ 3-5\n
2488        \1
2489        #msx,
2490        'Test the o recallCommand option',
2491    );
2492}
2493
2494# Test the dieLevel option
2495{
2496    my $wrapper = DebugWrap->new(
2497        {
2498            cmds =>
2499            [
2500                q/o dieLevel='1'/,
2501                q/c/,
2502                'q',
2503            ],
2504            prog => '../lib/perl5db/t/test-dieLevel-option-1',
2505        }
2506    );
2507
2508    $wrapper->output_like(qr#
2509        ^This\ program\ dies\.\ at\ \S+\ line\ 18\N*\.\n
2510        .*?
2511        ^\s+main::baz\(\)\ called\ at\ \S+\ line\ 13\n
2512        \s+main::bar\(\)\ called\ at\ \S+\ line\ 7\n
2513        \s+main::foo\(\)\ called\ at\ \S+\ line\ 21\n
2514        #msx,
2515        'Test the o dieLevel option',
2516    );
2517}
2518
2519# Test the warnLevel option
2520{
2521    my $wrapper = DebugWrap->new(
2522        {
2523            cmds =>
2524            [
2525                q/o warnLevel='1'/,
2526                q/c/,
2527                'q',
2528            ],
2529            prog => '../lib/perl5db/t/test-warnLevel-option-1',
2530        }
2531    );
2532
2533    $wrapper->contents_like(qr#
2534        ^This\ is\ not\ a\ warning\.\ at\ \S+\ line\ 18\N*\.\n
2535        .*?
2536        ^\s+main::baz\(\)\ called\ at\ \S+\ line\ 13\n
2537        \s+main::bar\(\)\ called\ at\ \S+\ line\ 25\n
2538        \s+main::myfunc\(\)\ called\ at\ \S+\ line\ 28\n
2539        #msx,
2540        'Test the o warnLevel option',
2541    );
2542}
2543
2544# Test the t command
2545{
2546    my $wrapper = DebugWrap->new(
2547        {
2548            cmds =>
2549            [
2550                't',
2551                'c',
2552                'q',
2553            ],
2554            prog => '../lib/perl5db/t/disable-breakpoints-1',
2555        }
2556    );
2557
2558    $wrapper->contents_like(qr/
2559        ^main::\([^:]+:15\):\n
2560        15:\s+\$dummy\+\+;\n
2561        main::\([^:]+:17\):\n
2562        17:\s+\$x\ =\ "FourthVal";\n
2563        /msx,
2564        'Test the t command (without a number.)',
2565    );
2566}
2567
2568# Test the o AutoTrace command
2569{
2570    my $wrapper = DebugWrap->new(
2571        {
2572            cmds =>
2573            [
2574                'o AutoTrace',
2575                'c',
2576                'q',
2577            ],
2578            prog => '../lib/perl5db/t/disable-breakpoints-1',
2579        }
2580    );
2581
2582    $wrapper->contents_like(qr/
2583        ^main::\([^:]+:15\):\n
2584        15:\s+\$dummy\+\+;\n
2585        main::\([^:]+:17\):\n
2586        17:\s+\$x\ =\ "FourthVal";\n
2587        /msx,
2588        'Test the o AutoTrace command',
2589    );
2590}
2591
2592# Test the t command with function calls
2593{
2594    my $wrapper = DebugWrap->new(
2595        {
2596            cmds =>
2597            [
2598                't',
2599                'b 18',
2600                'c',
2601                'x ["foo"]',
2602                'x ["bar"]',
2603                'q',
2604            ],
2605            prog => '../lib/perl5db/t/test-warnLevel-option-1',
2606        }
2607    );
2608
2609    $wrapper->contents_like(qr/
2610        ^main::\([^:]+:28\):\n
2611        28:\s+myfunc\(\);\n
2612        auto\(-\d+\)\s+DB<1>\s+t\n
2613        Trace\ =\ on\n
2614        auto\(-\d+\)\s+DB<1>\s+b\ 18\n
2615        auto\(-\d+\)\s+DB<2>\s+c\n
2616        main::myfunc\([^:]+:25\):\n
2617        25:\s+bar\(\);\n
2618        /msx,
2619        'Test the t command with function calls.',
2620    );
2621}
2622
2623# Test the o AutoTrace command with function calls
2624{
2625    my $wrapper = DebugWrap->new(
2626        {
2627            cmds =>
2628            [
2629                'o AutoTrace',
2630                'b 18',
2631                'c',
2632                'x ["foo"]',
2633                'x ["bar"]',
2634                'q',
2635            ],
2636            prog => '../lib/perl5db/t/test-warnLevel-option-1',
2637        }
2638    );
2639
2640    $wrapper->contents_like(qr/
2641        ^main::\([^:]+:28\):\n
2642        28:\s+myfunc\(\);\n
2643        auto\(-\d+\)\s+DB<1>\s+o\ AutoTrace\n
2644        \s+AutoTrace\s+=\s+'1'\n
2645        auto\(-\d+\)\s+DB<2>\s+b\ 18\n
2646        auto\(-\d+\)\s+DB<3>\s+c\n
2647        main::myfunc\([^:]+:25\):\n
2648        25:\s+bar\(\);\n
2649        /msx,
2650        'Test the o AutoTrace command with function calls.',
2651    );
2652}
2653
2654# Test the final message.
2655{
2656    my $wrapper = DebugWrap->new(
2657        {
2658            cmds =>
2659            [
2660                'c',
2661                'q',
2662            ],
2663            prog => '../lib/perl5db/t/test-warnLevel-option-1',
2664        }
2665    );
2666
2667    $wrapper->contents_like(qr/
2668        ^Debugged\ program\ terminated\.
2669        /msx,
2670        'Test the final "Debugged program terminated" message.',
2671    );
2672}
2673
2674# Test the o inhibit_exit=0 command
2675{
2676    my $wrapper = DebugWrap->new(
2677        {
2678            cmds =>
2679            [
2680                'o inhibit_exit=0',
2681                'n',
2682                'n',
2683                'n',
2684                'n',
2685                'q',
2686            ],
2687            prog => '../lib/perl5db/t/test-warnLevel-option-1',
2688        }
2689    );
2690
2691    $wrapper->contents_unlike(qr/
2692        ^Debugged\ program\ terminated\.
2693        /msx,
2694        'Test the o inhibit_exit=0 command.',
2695    );
2696}
2697
2698# Test the o PrintRet=1 option
2699{
2700    my $wrapper = DebugWrap->new(
2701        {
2702            cmds =>
2703            [
2704                'o PrintRet=1',
2705                'b 29',
2706                'c',
2707                q/$x = 's';/,
2708                'b 10',
2709                'c',
2710                'r',
2711                'q',
2712            ],
2713            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2714        }
2715    );
2716
2717    $wrapper->contents_like(
2718        qr/scalar context return from main::return_scalar: 20024/,
2719        "Test o PrintRet=1",
2720    );
2721}
2722
2723# Test the o PrintRet=0 option
2724{
2725    my $wrapper = DebugWrap->new(
2726        {
2727            cmds =>
2728            [
2729                'o PrintRet=0',
2730                'b 29',
2731                'c',
2732                q/$x = 's';/,
2733                'b 10',
2734                'c',
2735                'r',
2736                'q',
2737            ],
2738            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2739        }
2740    );
2741
2742    $wrapper->contents_unlike(
2743        qr/scalar context/,
2744        "Test o PrintRet=0",
2745    );
2746}
2747
2748# Test the o PrintRet=1 option in list context
2749{
2750    my $wrapper = DebugWrap->new(
2751        {
2752            cmds =>
2753            [
2754                'o PrintRet=1',
2755                'b 29',
2756                'c',
2757                q/$x = 'l';/,
2758                'b 17',
2759                'c',
2760                'r',
2761                'q',
2762            ],
2763            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2764        }
2765    );
2766
2767    $wrapper->contents_like(
2768        qr/list context return from main::return_list:\n0\s*'Foo'\n1\s*'Bar'\n2\s*'Baz'\n/,
2769        "Test o PrintRet=1 in list context",
2770    );
2771}
2772
2773# Test the o PrintRet=0 option in list context
2774{
2775    my $wrapper = DebugWrap->new(
2776        {
2777            cmds =>
2778            [
2779                'o PrintRet=0',
2780                'b 29',
2781                'c',
2782                q/$x = 'l';/,
2783                'b 17',
2784                'c',
2785                'r',
2786                'q',
2787            ],
2788            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2789        }
2790    );
2791
2792    $wrapper->contents_unlike(
2793        qr/list context/,
2794        "Test o PrintRet=0 in list context",
2795    );
2796}
2797
2798# Test the o PrintRet=1 option in void context
2799{
2800    my $wrapper = DebugWrap->new(
2801        {
2802            cmds =>
2803            [
2804                'o PrintRet=1',
2805                'b 29',
2806                'c',
2807                q/$x = 'v';/,
2808                'b 24',
2809                'c',
2810                'r',
2811                'q',
2812            ],
2813            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2814        }
2815    );
2816
2817    $wrapper->contents_like(
2818        qr/void context return from main::return_void/,
2819        "Test o PrintRet=1 in void context",
2820    );
2821}
2822
2823# Test the o PrintRet=1 option in void context
2824{
2825    my $wrapper = DebugWrap->new(
2826        {
2827            cmds =>
2828            [
2829                'o PrintRet=0',
2830                'b 29',
2831                'c',
2832                q/$x = 'v';/,
2833                'b 24',
2834                'c',
2835                'r',
2836                'q',
2837            ],
2838            prog => '../lib/perl5db/t/test-PrintRet-option-1',
2839        }
2840    );
2841
2842    $wrapper->contents_unlike(
2843        qr/void context/,
2844        "Test o PrintRet=0 in void context",
2845    );
2846}
2847
2848# Test the o frame option.
2849{
2850    my $wrapper = DebugWrap->new(
2851        {
2852            cmds =>
2853            [
2854                # This is to avoid getting the "Debugger program terminated"
2855                # junk that interferes with the normal output.
2856                'o inhibit_exit=0',
2857                'b 10',
2858                'c',
2859                'o frame=255',
2860                'c',
2861                'q',
2862            ],
2863            prog => '../lib/perl5db/t/test-frame-option-1',
2864        }
2865    );
2866
2867    $wrapper->contents_like(
2868        qr/
2869            in\s*\.=main::my_other_func\(3,\ 1200\)\ from.*?
2870            out\s*\.=main::my_other_func\(3,\ 1200\)\ from
2871        /msx,
2872        "Test o PrintRet=0 in void context",
2873    );
2874}
2875
2876{ # test t expr
2877    my $wrapper = DebugWrap->new(
2878        {
2879            cmds =>
2880            [
2881                # This is to avoid getting the "Debugger program terminated"
2882                # junk that interferes with the normal output.
2883                'o inhibit_exit=0',
2884                't fact(3)',
2885                'q',
2886            ],
2887            prog => '../lib/perl5db/t/fact',
2888        }
2889    );
2890
2891    $wrapper->contents_like(
2892        qr/
2893	    (?:^main::fact.*return\ \$n\ \*\ fact\(\$n\ -\ 1\);.*)
2894        /msx,
2895        "Test t expr",
2896    );
2897}
2898
2899# Test the w for lexical variables expression.
2900{
2901    my $wrapper = DebugWrap->new(
2902        {
2903            cmds =>
2904            [
2905                # This is to avoid getting the "Debugger program terminated"
2906                # junk that interferes with the normal output.
2907                'w $exp',
2908                'n',
2909                'n',
2910                'n',
2911                'n',
2912                'q',
2913            ],
2914            prog => '../lib/perl5db/t/break-on-dot',
2915        }
2916    );
2917
2918    $wrapper->contents_like(
2919        qr/
2920\s+old\ value:\s+'1'\n
2921\s+new\ value:\s+'2'\n
2922        /msx,
2923        "Test w for lexical values.",
2924    );
2925}
2926
2927# perl 5 RT #121509 regression bug.
2928# “perl debugger doesn't save starting dir to restart from2929# Thanks to Linda Walsh for reporting it.
2930{
2931    use File::Temp qw/tempdir/;
2932
2933    my $temp_dir = tempdir( CLEANUP => 1 );
2934
2935    local $ENV{__PERLDB_TEMP_DIR} = $temp_dir;
2936    my $wrapper = DebugWrap->new(
2937        {
2938            cmds =>
2939            [
2940                # This is to avoid getting the "Debugger program terminated"
2941                # junk that interferes with the normal output.
2942                'b _after_chdir',
2943                'c',
2944                'R',
2945                'b _finale',
2946                'c',
2947                'n',
2948                'n',
2949                'n',
2950                'n',
2951                'n',
2952                'n',
2953                'n',
2954                'n',
2955                'n',
2956                'n',
2957                'n',
2958                'n',
2959                'q',
2960            ],
2961            prog => '../lib/perl5db/t/rt-121509-restart-after-chdir',
2962        }
2963    );
2964
2965    $wrapper->output_like(
2966        qr/
2967In\ _finale\ No\ 1
2968    .*?
2969In\ _finale\ No\ 2
2970    .*?
2971In\ _finale\ No\ 3
2972        /msx,
2973        "Test that the debugger chdirs to the initial directory after a restart.",
2974    );
2975}
2976# Test the perldoc command
2977# We don't actually run the program, but we need to provide one to the wrapper.
2978SKIP:
2979{
2980    $^O eq "linux"
2981        or skip "man errors aren't especially portable", 1;
2982    -x '/usr/bin/man'
2983        or skip "man command seems to be missing", 1;
2984    local $ENV{LANG} = "C";
2985    local $ENV{LC_MESSAGES} = "C";
2986    local $ENV{LC_ALL} = "C";
2987    my $wrapper = DebugWrap->new(
2988        {
2989            cmds =>
2990            [
2991                'perldoc perlrules',
2992                'q',
2993            ],
2994            prog => '../lib/perl5db/t/fact',
2995        }
2996    );
2997
2998    $wrapper->output_like(
2999        qr/No (?:manual )?entry for perlrules/,
3000        'perldoc command works fine',
3001    );
3002}
3003
3004# [perl #71678] debugger bug in evaluation of user actions ('a' command)
3005# Still evaluated after the script finishes.
3006{
3007    my $wrapper = DebugWrap->new(
3008        {
3009            cmds =>
3010            [
3011                q#a 9 print " \$arg = $arg\n"#,
3012                'c 9',
3013                's',
3014                'q',
3015            ],
3016            prog => '../lib/perl5db/t/test-a-statement-2',
3017            switches => [ '-dw', ],
3018            stderr => 1,
3019        }
3020    );
3021
3022    $wrapper->contents_unlike(qr/
3023        Use\ of\ uninitialized\ value\ \$arg\ in\ concatenation\ [\S ]+\ or\ string\ at
3024        /msx,
3025        'Test that the a command does not emit warnings on program exit.',
3026    );
3027}
3028
3029{
3030    # GitHub #17901
3031    my $wrapper = DebugWrap->new(
3032        {
3033            cmds =>
3034            [
3035                'a 4 $s++',
3036                ('s') x 5,
3037                'x $s',
3038                'q'
3039            ],
3040            prog => '../lib/perl5db/t/test-a-statement-3',
3041            switches => [ '-d' ],
3042            stderr => 0,
3043        }
3044    );
3045    $wrapper->contents_like(
3046        qr/^0 +2$/m,
3047        'Test that the a command runs only on the given lines.',
3048    );
3049}
3050
3051{
3052    # perl 5 RT #126735 regression bug.
3053    local $ENV{PERLDB_OPTS} = "NonStop=0 RemotePort=non-existent-host.tld:9001";
3054    my $output = runperl( stdin => "q\n", stderr => 1, switches => [ '-d' ], prog => '../lib/perl5db/t/fact' );
3055    like(
3056        $output,
3057        qr/^Unable to connect to remote host:/ms,
3058        'Tried to connect.',
3059    );
3060    unlike(
3061        $output,
3062        qr/syntax error/,
3063        'Can quit from the debugger after a wrong RemotePort',
3064    );
3065}
3066
3067{
3068    # perl 5 RT #120174 - 'p' command
3069    my $wrapper = DebugWrap->new(
3070        {
3071            cmds =>
3072            [
3073                'b 2',
3074                'c',
3075                'p@abc',
3076                'q',
3077            ],
3078            prog => '../lib/perl5db/t/rt-120174',
3079        }
3080    );
3081
3082    $wrapper->contents_like(
3083        qr/1234/,
3084        q/RT 120174: p command can be invoked without space after 'p'/,
3085    );
3086}
3087
3088{
3089    # perl 5 RT #120174 - 'x' command on array
3090    my $wrapper = DebugWrap->new(
3091        {
3092            cmds =>
3093            [
3094                'b 2',
3095                'c',
3096                'x@abc',
3097                'q',
3098            ],
3099            prog => '../lib/perl5db/t/rt-120174',
3100        }
3101    );
3102
3103    $wrapper->contents_like(
3104        qr/0\s+1\n1\s+2\n2\s+3\n3\s+4/ms,
3105        q/RT 120174: x command can be invoked without space after 'x' before array/,
3106    );
3107}
3108
3109{
3110    # perl 5 RT #120174 - 'x' command on array ref
3111    my $wrapper = DebugWrap->new(
3112        {
3113            cmds =>
3114            [
3115                'b 2',
3116                'c',
3117                'x\@abc',
3118                'q',
3119            ],
3120            prog => '../lib/perl5db/t/rt-120174',
3121        }
3122    );
3123
3124    $wrapper->contents_like(
3125        qr/\s+0\s+1\n\s+1\s+2\n\s+2\s+3\n\s+3\s+4/ms,
3126        q/RT 120174: x command can be invoked without space after 'x' before array ref/,
3127    );
3128}
3129
3130{
3131    # perl 5 RT #120174 - 'x' command on hash ref
3132    my $wrapper = DebugWrap->new(
3133        {
3134            cmds =>
3135            [
3136                'b 4',
3137                'c',
3138                'x\%xyz',
3139                'q',
3140            ],
3141            prog => '../lib/perl5db/t/rt-120174',
3142        }
3143    );
3144
3145    $wrapper->contents_like(
3146        qr/\s+'alpha'\s+=>\s+'beta'\n\s+'gamma'\s+=>\s+'delta'/ms,
3147        q/RT 120174: x command can be invoked without space after 'x' before hash ref/,
3148    );
3149}
3150
3151{
3152    # gh #17660
3153    my $wrapper = DebugWrap->new(
3154        {
3155            cmds =>
3156            [
3157                'b 13',
3158                'c',
3159                'i Foo',
3160                'q',
3161            ],
3162            prog => '../lib/perl5db/t/gh-17660',
3163        }
3164    );
3165
3166    $wrapper->output_unlike(
3167        qr/Undefined subroutine &mro::get_linear_isa/ms,
3168        q/mro needs to be loaded/,
3169       );
3170    $wrapper->output_like(
3171        qr/Foo 1.000, Bar 2.000/,
3172        q/check for reasonable result/,
3173       );
3174}
3175
3176{
3177    # gh #17661
3178    my $wrapper = DebugWrap->new(
3179        {
3180            cmds =>
3181            [
3182                'c',
3183                'i $obj',
3184                'q',
3185            ],
3186            prog => '../lib/perl5db/t/gh-17661',
3187        }
3188    );
3189
3190    $wrapper->output_like(
3191        qr/C5, C1, C2, C3, C4/,
3192        q/check for reasonable result/,
3193       );
3194}
3195
3196{
3197    # gh #17661 related - C<l $var> where $var is lexical
3198    my $wrapper = DebugWrap->new(
3199        {
3200            cmds =>
3201            [
3202                'c',
3203                'l $x',
3204                'l $y',
3205                'q',
3206            ],
3207            prog => '../lib/perl5db/t/gh-17661b',
3208        }
3209    );
3210
3211    $wrapper->contents_like(
3212        qr/sub bar/,
3213        q/check bar was listed/,
3214       );
3215    $wrapper->contents_like(
3216        qr/sub foo/,
3217        q/check foo was listed/,
3218       );
3219}
3220
3221SKIP:
3222{
3223    $Config{usethreads}
3224      or skip "need threads to test debugging threads", 1;
3225    my $wrapper = DebugWrap->new(
3226        {
3227            cmds =>
3228            [
3229                'c',
3230                'q',
3231            ],
3232            prog => '../lib/perl5db/t/rt-124203',
3233        }
3234    );
3235
3236    $wrapper->output_like(qr/In the thread/, "[perl #124203] the thread ran");
3237
3238    $wrapper->output_like(qr/Finished/, "[perl #124203] debugger didn't deadlock");
3239
3240    $wrapper = DebugWrap->new(
3241        {
3242            cmds =>
3243            [
3244                'c',
3245                'q',
3246            ],
3247            prog => '../lib/perl5db/t/rt-124203b',
3248        }
3249    );
3250
3251    $wrapper->output_like(qr/In the thread/, "[perl #124203] the thread ran (lvalue)");
3252
3253    $wrapper->output_like(qr/Finished One/, "[perl #124203] debugger didn't deadlock (lvalue)");
3254}
3255
3256{
3257    # https://github.com/Perl/perl5/issues/19198
3258    # this isn't a debugger bug, but a bug in the way perl itself stores cop
3259    # information for lines
3260    my $wrapper = DebugWrap->new(
3261        {
3262            cmds =>
3263            [
3264                'b Test::AUTOLOAD', # this would crash on ASAN
3265                'c', # this would fail to stop at the breakpoint
3266                'q'
3267            ],
3268            prog => \<<'EOS',
3269package Test;
3270
3271sub AUTOLOAD {
3272    use vars '$AUTOLOAD';
3273    my $sub = $AUTOLOAD;
3274    return 1;
3275}
3276
3277package main;
3278
3279
3280sub test
3281{
3282    Test::test();
3283}
3284
3285sub test_test
3286{
3287    eval { test() };
3288}
3289
3290test_test();
3291EOS
3292           }
3293    );
3294    $wrapper->output_unlike(qr/AddressSanitizer/, "[github #19198] no bad access");
3295    $wrapper->contents_like(qr/^Test::AUTOLOAD\(.*?\):\s+\d+:\s+my \$sub = \$AUTOLOAD;/m,
3296                          "[github #19198] check we stopped correctly");
3297}
3298
3299{
3300    # gh-21350: verify that nonsense linespecs are rejected #1
3301    my $wrapper = DebugWrap->new(
3302        {
3303            cmds =>
3304            [
3305                'l ...',
3306                'q',
3307            ],
3308            prog => '../lib/perl5db/t/gh-21350',
3309        }
3310    );
3311
3312    $wrapper->contents_like(
3313        qr/Invalid line specification '...'/,
3314        q/gh-21350: multiple periods rejected/,
3315    );
3316}
3317
3318{
3319    # gh-21350: verify that nonsense linespecs are rejected #2
3320    my $wrapper = DebugWrap->new(
3321        {
3322            cmds =>
3323            [
3324                'l $',
3325                'q',
3326            ],
3327            prog => '../lib/perl5db/t/gh-21350',
3328        }
3329    );
3330
3331    $wrapper->contents_like(
3332        qr/Invalid line specification '\$'/,
3333        q/gh-21350: $ rejected/,
3334    );
3335}
3336
3337{
3338    # gh-21350: verify that nonsense linespecs are rejected #3
3339    my $wrapper = DebugWrap->new(
3340        {
3341            cmds =>
3342            [
3343                'l 2.71828',
3344                'q',
3345            ],
3346            prog => '../lib/perl5db/t/gh-21350',
3347        }
3348    );
3349
3350    $wrapper->contents_like(
3351        qr/Invalid line specification '2\.71828'/,
3352        q/gh-21350: floating-point rejected/,
3353    );
3354}
3355
3356{
3357    # gh-21350: verify that nonsense linespecs are rejected #4
3358    my $wrapper = DebugWrap->new(
3359        {
3360            cmds =>
3361            [
3362                'l 1.1.1.1',
3363                'q',
3364            ],
3365            prog => '../lib/perl5db/t/gh-21350',
3366        }
3367    );
3368
3369    $wrapper->contents_like(
3370        qr/Invalid line specification '1\.1\.1\.1'/,
3371        q/gh-21350: IPv4 address rejected/,
3372    );
3373}
3374
3375{
3376    # gh-21350: verify that nonsense linespecs are rejected #5
3377    my $wrapper = DebugWrap->new(
3378        {
3379            cmds =>
3380            [
3381                'l -.',
3382                'q',
3383            ],
3384            prog => '../lib/perl5db/t/gh-21350',
3385        }
3386    );
3387
3388    $wrapper->contents_like(
3389        qr/Invalid line specification '-\.'/,
3390        q/gh-21350: invalid partial range rejected/,
3391    );
3392}
3393
3394{
3395    # gh-21350: verify that nonsense linespecs are rejected #6
3396    my $wrapper = DebugWrap->new(
3397        {
3398            cmds =>
3399            [
3400                'l -$.',
3401                'q',
3402            ],
3403            prog => '../lib/perl5db/t/gh-21350',
3404        }
3405    );
3406
3407    $wrapper->contents_like(
3408        qr/Invalid line specification '\-\$\.'/,
3409        q/gh-21350: formerly acceptable nonsense rejected/,
3410    );
3411}
3412
3413{
3414    # gh-21350: verify that nonsense linespecs are rejected #7
3415    my $wrapper = DebugWrap->new(
3416        {
3417            cmds =>
3418            [
3419                'l -12',
3420                'q',
3421            ],
3422            prog => '../lib/perl5db/t/gh-21350',
3423        }
3424    );
3425
3426    $wrapper->contents_like(
3427        qr/Invalid line specification '-12'/,
3428        q/gh-21350: negative line number rejected/,
3429    );
3430}
3431
3432{
3433    # gh-21350: verify that nonsense linespecs are rejected #8
3434    my $wrapper = DebugWrap->new(
3435        {
3436            cmds =>
3437            [
3438                'l 17$',
3439                'q',
3440            ],
3441            prog => '../lib/perl5db/t/gh-21350',
3442        }
3443    );
3444
3445    $wrapper->contents_like(
3446        qr/Invalid line specification '17\$'/,
3447        q/gh-21350: line number with trailing $ rejected/,
3448    );
3449}
3450
3451{
3452    # gh-21350: verify that nonsense linespecs are rejected #9
3453    my $wrapper = DebugWrap->new(
3454        {
3455            cmds =>
3456            [
3457                'l $2250$',
3458                'q',
3459            ],
3460            prog => '../lib/perl5db/t/gh-21350',
3461        }
3462    );
3463
3464    $wrapper->contents_like(
3465        qr/Invalid line specification '\$2250\$'/,
3466        q/gh-21350: match variable with trailing $ rejected/,
3467    );
3468}
3469
3470{
3471    # https://github.com/Perl/perl5/issues/21564
3472    # not a debugger bug, but with the way the fix for #19198 was broken
3473    # this needs to be tested with a debugger of some sort (even a no-op
3474    # debugger) so test it here.
3475    my $wrapper = DebugWrap->new(
3476        {
3477            cmds =>
3478            [
3479                'c', # just run it, we check the output of the code
3480                'q'
3481            ],
3482            prog => \<<'EOS',
3483use v5.12;
3484no strict;
3485use B qw(svref_2object SVf_IOK);
3486my $sv = svref_2object(\(${"_<$0"}[3])); # the "use B;" line
3487say +($sv->FLAGS & SVf_IOK) ? "OK" : "FAIL";
3488EOS
3489        }
3490    );
3491    $wrapper->output_like(qr/\bOK\b/, "check the line is IOK");
3492}
3493
3494done_testing();
3495
3496END {
3497    1 while unlink ($rc_filename, $out_fn);
3498}
3499