NAME

Devel::TestEmbed - extend the debugger with Test::More

SYNOPSIS

# 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");

DESCRIPTION

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.

THE HACK

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:

  • Load Test::More into the program's namespace.

  • Load this module into the debugger's namespace.

  • Turn on the magical flag that tells the debugger to run a 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).

Debugger's default behavior

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.

How it all comes together

First the debugger gets up and running.

1. Perl starts and sees -d on the command line. It loades the debugger.
2. The debugger initializes, looks for .perldb and executes it.
3. .perldb defines afterinit and watchfunction.
4. Perl calls afterinit.
5. afterinit loads Devel::TestEmbed and stacks use Test::More plan=&lt;no_plan on the debugger's typeahead stack, @DB::typeahead.
6. The debugger calls watchfunction, which installs tdump into the current namespace.
7. The debugger starts reading commands, and pulls the use off the typeahead stack and executes it.
8. The debugger finally prompts the user for input.

Now everything's in place. If we enter a Test::More sub:

1. The debugger decides it doesn't understand the line.
2. The debugger evaluates the line in the current namespace.
3. The proper Test::More sub is called, and the test runs.
4. The debugger saves the line on @DB::hist (its command history).

If we enter tdump something:

1. The debugger decides it doesn't understand this either.
2. The debugger evaluates the line in the current namespace. Since tdump has been imported there. it runs.
3. tdump ferrets through @DB::hist and extracts anything which matches its list of "subs found in Test::More that are tests".
4. tdump writes the file and prints a "hi, I saved your tests" message.

SUBROUTINES

tdump

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.

BUGS

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.

SEE ALSO

Devel::Command for a considerably better way to do this. perl5db.pl for a detailed description of how afterinit and watchfunction work.

AUTHOR

Joe McMahon <mcmahon@cpan.org<gt>.