I'm fixing a large test script (> 1000 lines) that uses some utility methods (also > 1000 lines) to perform repeated tests on various initial data setups. This helps consolidate code. However, when a test fails it reports the line number of inside the utility method making it hard to trace which test failed.
Is it possible to configure Test::Most to give a stacktrace instead of just a single line number when a test fails?
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Test::Most tests => 3;
ok(1, 'first test');
note "The following includes a failed test, but a stack trace would be more helpful";
helper_sub_with_test(); # Line 13
ok(1, 'third test');
sub helper_sub_with_test {
ok(0, "second test"); # Line 17
}
Outputs:
$ perl scratch.pl
1..3
ok 1 - first test
# The following includes a failed test, but a stack trace would be more helpful
not ok 2 - second test
# Failed test 'second test'
# at scratch.pl line 17.
ok 3 - third test
# Looks like you failed 1 test of 3.
As you can see, it would be helpful if the failed test reported both line 17 and line 13 for when there are multiple calls to the utility method.
I don't believe that the Test::More infrastructure provides such a beastie, but do you really need a stack trace? Reporting line 13 alone should be sufficient, provided you give your tests descriptive names.
To report line 13 instead of line 17, just add the following to your sub:
local $Test::Builder::Level = $Test::Builder::Level + 1;
Longer example:
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Test::Most tests => 3;
ok(1, 'first test');
note "The following includes a failed test, but a stack trace would be more helpful";
helper_sub_with_test(); # Line 13
ok(1, 'third test');
sub helper_sub_with_test {
local $Test::Builder::Level = $Test::Builder::Level + 1;
ok(0, sprintf "second test (look at line %d)", __LINE__); # Line 18
}
The quick and dirty way to get what you want is to put a wrapper around Test::Builder::ok. This is how Test::Most operates.
Using Aspect makes this less of a hack.
use Carp qw(longmess);
use Test::Most;
use Aspect;
after {
# For some reason, the return value is not being captured by Aspect
my $last_test = ($_->self->summary)[-1];
print longmess if !$last_test;
} call "Test::Builder::ok";
sub foo { ok(0) }
foo();
pass;
done_testing;
Related
I am trying to get started using Device::BlinkyTape::SimulationPort, but when executing the simple example script below, I get the error:
'x' outside of string in unpack at /home/pi/perl5/lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70.
Any idea how I can get it to work?
#!/usr/bin/env perl
use lib '../lib';
use Device::BlinkyTape::WS2811; # BlinkyTape uses WS2811
my $bb = Device::BlinkyTape::WS2811->new(simulate => 1);
$bb->all_on();
sleep 2;
$bb->all_off();
sleep 2;
$bb->send_pixel(255,255,255);
$bb->show();
sleep 2;
$bb->send_pixel(255,0,0);
$bb->show();
sleep 2;
$bb->send_pixel(240,0,0);
$bb->show();
sleep 2;
# Go crazy
for (my $b=0; $b<=1000; $b++) {
for (my $a=0; $a<=59; $a++) {
$bb->send_pixel(int(rand(254)),int(rand(254)),int(rand(254)));
}
$bb->show(); # shows the sent pixel row
}
sleep 2;
It looks like a bug in the module.
The Device::BlinkyTape POD BUGS section states:
The device is not yet available so the module has been implemented by
inspecting partly undocumented and unfinished code in other languages.
The module was last updated 8 years ago (2013); perhaps it is just a work-in-progress.
The module has no meaningful tests, as can be seen from the CPAN Testers results and the lack of Coverage results. Thus, there is no public evidence that the module works.
The code posted in the Question is from the simulate.pl example. Here is a minimal example which reproduces the problem:
use diagnostics;
use Device::BlinkyTape::WS2811;
my $bb = Device::BlinkyTape::WS2811->new(simulate => 1);
$bb->all_on();
I added diagnostics to get more information about the error. Here is my output:
simulation on. at lib/perl5/Device/BlinkyTape.pm line 114.
'x' outside of string in unpack at
lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70 (#1)
(F) You had a pack template that specified a relative position after
the end of the string being unpacked. See "pack" in perlfunc.
Uncaught exception from user code:
'x' outside of string in unpack at lib/perl5/Device/BlinkyTape/SimulationPort.pm line 70.
Device::BlinkyTape::SimulationPort::write(Device::BlinkyTape::SimulationPort=HASH(0x348b050), "\x{fe}") called at lib/perl5/Device/BlinkyTape/WS2811.pm line 34
Device::BlinkyTape::WS2811::send_pixel(Device::BlinkyTape::WS2811=HASH(0x3481fe0), 255, 255, 255) called at lib/perl5/Device/BlinkyTape.pm line 137
Device::BlinkyTape::all_on(Device::BlinkyTape::WS2811=HASH(0x3481fe0)) called at line 4
Here is line 70:
my $b = unpack("x2 C1", $color);
The next step is to report this issue and try to get an update on the status of the module.
I am trying to create unit tests for my script using the Test::More and Test::Exception libraries.
I have read these articles How to test for exceptions in Perl and Test::Exception.
The first article describes exactly what I need, to test my subroutine for throwing exception or dieing.
But I cannot get it working. Consider some examples
#!/usr/bin/env perl
package My::SuperModule;
use strict;
use warnings;
use Net::Ping;
use Utils::Variables::Validator;
sub new
{
die "Hello";
#Getting class name from, stored in $_[0]
my $class = shift;
#Getting user name from arguments $_[1]
my $user_name = shift;
........
}
And my test file
use warnings; # this warns you of bad practices
use strict; # this prevents silly errors
use Test::More; # for the is() and isnt() functions
use Test::Exception;
do './My/SuperModule.pm';
#Testing module loading
print "=================Testing module loading=================\n";
use_ok ( 'My::SuperModule' );
use_ok ( 'My::SuperModule', 'new' );
#Testing module subroutines
dies_ok { My::SuperModule->new() } "Died in class constructor";
sub div {
my ( $a, $b ) = #_;
return $a / $b;
};
dies_ok { div( 1, 0 ) } 'divide by zero detected';
It stops executing script in any case, but I need just to handle if died, I need to test this because I manually invoke die if data is invalid or something other , but it dies and doesn't continue to execute the script further. Giving me a message
Uncaught exception from user code:
Hello at ../libs/My/SuperModule.pm line 31.
My::SuperModule::new('My::SuperModule', '') called at SuperModule.t line 24
# Tests were run but no plan was declared and done_testing() was not seen.
# Looks like your test exited with 2 just after 8.
But if to use division by zero it works like I want
ok 16 - divide by zero detected
So it fails but doesn't terminate execution of the script.
I am newbie in Perl, so cannot solve the problem by myself, maybe there is not problem at all, just no way to do what I want.
Please suggest what to do or say where is my fault here.
EDIT
I have just tried to divide by zero inside my module new subroutine and here is the message I got.
Illegal division by zero at ../libs/My/SuperModule.pm line 33 (#1)
(F) You tried to divide a number by 0. Either something was wrong in
your logic, or you need to put a conditional in to guard against
meaningless input.
I really cannot figure out what is going on. Please help with this.
Here is a minimal example that works:
package My::SuperModule;
use strict;
use warnings;
sub new {
die "Hello";
}
package main;
run() unless caller;
use Test::More;
use Test::Exception;
sub run {
dies_ok { My::SuperModule->new } "dies ok";
done_testing;
}
Output:
C:\...\t> prove -v my.pl
my.pl ..
ok 1 - dies ok
1..1
ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.09 usr + 0.00 sys = 0.09 CPU)
Result: PASS
Note that, for the purpose of providing a self-contained example, I combined the module code and the test script into a single file.
Also note that I did not clutter the test script with unnecessary print statements.
If you want, you can use diag to show some output:
diag "Checking if Test::Exception::dies_ok will catch die in new";
dies_ok { My::SuperModule->new } "dies ok";
done_testing;
Output:
C:\...\t> prove my.pl
my.pl .. # Checking if Test::Exception::dies_ok will catch die in new
my.pl .. ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.05 usr + 0.02 sys = 0.06 CPU)
Result: PASS
As opposed to plain print statements, diag output will actually be shown when tests are run from a harness such as prove.
It works for me. All I needed to do was:
Comment out the two modules that the test wasn't using (Net::Ping and Utils::Variables::Validator - I don't have them installed).
Add 1; as the last line of the module - so it returns a true value.
Remove the extra require and use_ok from the test.
Added done_testing; to the end of the test - so the test harness knows that it got to the end of the tests.
You probably don't care about the first item on that list, but if you fix the others, it should work for you.
use DateTime::TimeZone::Local;
use Test::More tests => 1;
my #input = (1 .. 10 );
my (#output) = sort {
DateTime::TimeZone::Local->TimeZone();
$a cmp $b
} #input;
is_deeply(\#output, \#input);
Output:
1..1
Can't return outside a subroutine at /usr/local/share/perl/5.8.8/DateTime/TimeZone/Local.pm line 72.
# Looks like your test exited with 9 before it could output anything.
shell returned 9
I have checked and it definitely is inside a sub routine. It doesn't appear to be anything to do with the module used, this code also causes the same error:
my #output = sort {
sub1();
} (1 .. 5);
sub sub1 {
eval "use ModuleDoesntExist";
return 1; # remove this and get a seg fault
}
Looks like it is a bug in perl more than anything. Any ideas? More interested in why this is happening than a workaround - it only occurs if the module doesn't exist.
It looks as though it is actually a bug in Perl. See this thread on the Perl Porters list.
I know that the BEGIN block is compiled and executed before the main body of a Perl program. If you're not sure of that just try running the command perl -cw over this:
#!/ms/dist/perl5/bin/perl5.8
use strict;
use warnings;
BEGIN {
print "Hello from the BEGIN block\n";
}
END {
print "Hello from the END block\n";
}
I have been taught that early compilation and execution of a BEGIN block lets a programmer ensure that any needed resources are available before the main program is executed.
And so I have been using BEGIN blocks to make sure that things like DB connections have been established and are available for use by the main program. Similarly, I use END blocks to ensure that all resources are closed, deleted, terminated, etc. before the program terminates.
After a discussion this morning, I am wondering if this the wrong way to look at BEGIN and END blocks.
What is the intended role of a BEGIN block in Perl?
Update 1: Just found out why the DBI connect didn't work. After being given this little Perl program:
use strict;
use warnings;
my $x = 12;
BEGIN {
$x = 14;
}
print "$x\n";
when executed it prints 12.
Update 2: Thanks to Eric Strom's comment below this new version makes it clearer:
use strict;
use warnings;
my $x = 12;
my $y;
BEGIN {
$x = 14;
print "x => $x\n";
$y = 16;
print "y => $y\n";
}
print "x => $x\n";
print "y => $y\n";
and the output is
x => 14
y => 16
x => 12
y => 16
Once again, thanks Eric!
While BEGIN and END blocks can be used as you describe, the typical usage is to make changes that affect the subsequent compilation.
For example, the use Module qw/a b c/; statement actually means:
BEGIN {
require Module;
Module->import(qw/a b c/);
}
similarly, the subroutine declaration sub name {...} is actually:
BEGIN {
*name = sub {...};
}
Since these blocks are run at compile time, all lines that are compiled after a block has run will use the new definitions that the BEGIN blocks made. This is how you can call subroutines without parenthesis, or how various modules "change the way the world works".
END blocks can be used to clean up changes that the BEGIN blocks have made but it is more common to use objects with a DESTROY method.
If the state that you are trying to clean up is a DBI connection, doing that in an END block is fine. I would not create the connection in a BEGIN block though for several reasons. Usually there is no need for the connection to be available at compile time. Performing actions like connecting to a database at compile time will drastically slow down any editor you use that has syntax checking (because that runs perl -c).
Have you tried swapping out the BEGIN{} block for an INIT{} block? That's the standard approach for things like modperl which use the "compile-once, run-many" model, as you need to initialize things anew on each separate run, not just once during the compile.
But I have to ask why it's all in special block anyway. Why don't you just make some sort of prepare_db_connection() function, and then call it as you need to when the program starts up?
Something that won't work in a BEGIN{} will also have the same problem if it's main-line code in a module file that gets used. That's another possible reason to use an INIT{} block.
I've also seen deadly-embrace problems of mutual recursion that have to be unravelled using something like an require instead of use, or an INIT{} instead of a BEGIN{}. But that's pretty rare.
Consider this program:
% cat sto-INIT-eg
#!/usr/bin/perl -l
print " PRINT: main running";
die " DIE: main dying\n";
die "DIE XXX /* NOTREACHED */";
END { print "1st END: done running" }
CHECK { print "1st CHECK: done compiling" }
INIT { print "1st INIT: started running" }
END { print "2nd END: done running" }
BEGIN { print "1st BEGIN: still compiling" }
INIT { print "2nd INIT: started running" }
BEGIN { print "2nd BEGIN: still compiling" }
CHECK { print "2nd CHECK: done compiling" }
END { print "3rd END: done running" }
When compiled only, it produces:
% perl -c sto-INIT-eg
1st BEGIN: still compiling
2nd BEGIN: still compiling
2nd CHECK: done compiling
1st CHECK: done compiling
sto-INIT-eg syntax OK
While when compiled and executed, it produces this:
% perl sto-INIT-eg
1st BEGIN: still compiling
2nd BEGIN: still compiling
2nd CHECK: done compiling
1st CHECK: done compiling
1st INIT: started running
2nd INIT: started running
PRINT: main running
DIE: main dying
3rd END: done running
2nd END: done running
1st END: done running
And the shell reports an exit of 255, per the die.
You should be able to arrange to have the connection happen when you need it to, even if a BEGIN{} proves too early.
Hm, just remembered. There's no chance you're doing something with DATA in a BEGIN{}, is there? That's not set up till the interpreter runs; it's not open to the compiler.
While the other answers are true, I find it also worth to mention the use of BEGIN and END blocks when using the -n or -p switches to Perl.
From http://perldoc.perl.org/perlmod.html
When you use the -n and -p switches to Perl, BEGIN and END work just as they do in awk, as a degenerate case.
For those unfamiliar with the -n switch, it tells Perl to wrap the program with:
while (<>) {
... # your program goes here
}
http://perldoc.perl.org/perlrun.html#Command-Switches if you're interested about more specific information about Perl switches.
As an example to demonstrate the use of BEGIN with the -n switch, this Perl one-liner enumerates the lines of the ls command:
ls | perl -ne 'BEGIN{$i = 1} print "$i: $_"; $i += 1;'
In this case, the BEGIN-block is used to initiate the variable $i by setting it to 1 before processing the lines of ls. This example will output something like:
1: foo.txt
2: bar.txt
3: program.pl
4: config.xml
I'm using ActivePerl 5.8 on Windows XP.
use strict;
use warnings;
use Data::Dumper;
There are three subroutines used in my script.
To detect the call stack, I can only insert some print "some location"; and check the print result from console Window.
Is there any good method to monitor it? Thank you.
If it's your code, you might want to use:
Carp::cluck( "And here's the stack:" );
See Carp::cluck. It prints out a warning with a stack trace. It works like the "printf" style of debug output.
Use the debugger's T command.
Example:
$ perl -d -e'
sub foo {}
sub bar { foo; }
bar;
'
Loading DB routines from perl5db.pl version 1.32
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(-e:4): bar;
DB<1> s
main::bar(-e:3): sub bar { foo; }
DB<1> s
main::foo(-e:2): sub foo {}
DB<1> T
. = main::foo() called from -e line 3
. = main::bar() called from -e line 4
DB<1> s
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB<1> q
You weren't specific about why you'd like to monitor the call stack and trace your subs, so answers will have to be broad.
One method is caller:
caller
Returns the context of the current subroutine call. In scalar context, returns the caller's package name if there is a caller, that is, if we're in a subroutine or eval or require, and the undefined value otherwise. In list context, returns
# 0 1 2
($package, $filename, $line) = caller;
With EXPR, it returns some extra information that the debugger uses to print a stack trace. The value of EXPR indicates how many call frames to go back before the current one.
# 0 1 2 3 4
($package, $filename, $line, $subroutine, $hasargs,
# 5 6 7 8 9 10
$wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
= caller($i);
You might also use the Devel::Cover module:
Code coverage data are collected using a pluggable runops function which counts how many times each op is executed. These data are then mapped back to reality using the B compiler modules. There is also a statement profiling facility which needs a better backend to be really useful.
The more you tell us about what you want to do, the more helpful to you our answers will be!
You rarely need to directly manage the call stack in Perl. If you do caller is the tool you want. However, it is only rarely needed.
More often, I want to see a stack trace when I am debugging. Good news, its easy to get a stack trace, simply use Carp's confess and cluck functions instead of die and warn.
use strict;
use warnings;
use Carp;
bar(6.1);
bar(1);
sub foo {
confess "Oh noes" unless #_ == 6; # confess is fatal
}
sub bar {
my $count = shift;
cluck "bar is in trouble" unless int $count == $count; # cluck is not fatal
foo( ('a')x $count );
}
This gets you:
dao:~ toad$ perl test.pl
bar is in trouble at test.pl line 14
main::bar(6.1) called at test.pl line 5
Oh noes at test.pl line 9
main::foo('a') called at test.pl line 15
main::bar(1) called at test.pl line 6