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