Devel::TestEmbed - extend the debugger with Test::More
# We assume that the supplied perldb.sample has been # copied to the appropriate place. $ perl -demo Loading DB routines from perl5db.pl version 1.27 Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(-e:1): mo auto(-1) DB<1> use Test::More qw(no_plan)
DB<2> use_ok("CGI");
DB<3> $obj = new CGI;
DB<4> # Keep 'new CGI' in our test
DB<5> isa_ok($obj, "CGI")
ok 2 - The object isa CGI
DB<6> tdump "our.t"
Recording tests for this session in our.t ... done (2 tests).
DB<7> q
1..2
$ cat our.t
use Test::More tests=>2;
use_ok("CGI");
# Keep 'new CGI' in our test
$obj = new CGI;
isa_ok($obj, "CGI");
The Devel::TestEmbed module loads Test::More for you, allowing you to
use its functions to test code; you may then save the tests you used in this
debugger session via the tdump function.
If needed, you may save "setup" code in the test as well by entering a comment at the debugger prompt after each line of such code.
The module defines an afterinit and watchfunction; you will need to take this into account
if you wish to defined either of these yourself while using this function. See perldoc perl5db.pl
for more informaton on these routines.
This solution to extending the debugger is a hack using the debugger's default behaviors in conjunction with some non-standard uses of the debugger's standard interfaces.
afterinit()The debugger allows you to define an afterinit function in .perldb (the debugger's
equivalent to a .rc or <init> file). afterinit gets called, not surprisingly, after
the debugger has finished its initialization and before it prompts the user for the first
command.
This allows us to do a number of things on behalf of the user:
Test::More into the program's namespace.
watchfunction.
watchfunction()watchfunction() gets called just before the command loop starts. We use it to
install the tdump() subroutine into the current namespace (whatever namespace
that happens to be).
When the debugger gets a command line it doesn't understand, it assumes that it
mus be a Perl expression, so it goes ahead and evaluates this expression in the
context of the program being debugged. This is what allows you to just say
print $blah and have it actually be $blah from your program, not the
debugger.
First the debugger gets up and running.
-d on the command line. It loades the debugger.
.perldb and executes it.
.perldb defines afterinit and watchfunction.
afterinit.
afterinit loads Devel::TestEmbed and stacks use Test::More plan=<no_plan on the debugger's typeahead stack, @DB::typeahead.
watchfunction, which installs tdump into the current namespace.
use off the typeahead stack and executes it.
Now everything's in place. If we enter a Test::More sub:
Test::More sub is called, and the test runs.
@DB::hist (its command history).
If we enter tdump something:
tdump has been imported there. it runs.
tdump ferrets through @DB::hist and extracts anything which matches its list of "subs found in Test::More that are tests".
tdump writes the file and prints a "hi, I saved your tests" message.
This is the actual command code that searches through the debugger's history and writes the test file. It takes an optional argument of the string to be used as the file name.
The "command" doesn't get to parse the debugger command line itself, so if you say
something like tdump foo.t without quotes around the foo.t, you'll find that
Perl has evaluated this as an expression and merrily written your test to the file
foot.
Package switching in the debugger is not captured.
Tests which have been dumped once get dumped again if you use tdump multiple times.
Running the debugger with this enabled can vastly slow down the execution of your program,
because watchfunction is getting called every time a line of your program executes.
The tdump routine is forcibly imported into every package when execution goes to that
package. If that package has its own tdump routine, chaos is likely to result.
You should be using Devel::Command instead of this module if you want a nice clean
implementation of debugger command extensions.
Devel::Command for a considerably better way to do this.
perl5db.pl for a detailed description of how afterinit and watchfunction work.
Joe McMahon <mcmahon@cpan.org