How to use Devel::Cover with prove? - perl

I see there are some similar questions here and on http://www.perlmonks.org but I still do not get it.
Imagine I have a project with a 'lib/' and a 't' directories. I run my tests with 'prove':
$ cd $PROJECT_ROOT
$ prove ./*.t
I want to get a report in html for one or more files in the 'lib/' directory. I do not want reports for the files in the 't' directory.
A simple example should be enough. Thanks

perl Makefile.PL or perl Build.PL
cover -test

The proper way is to always start out with Makefile.PL/Build.PL, just as selected answer suggests. However, sometimes you are not the one who started out, so...
I used to make a fake makefile:
% cat Makefile
test:
prove -Ilib -r t
The following also seems to work (w/o touching ANY files on disk):
cover -t -make 'prove -Ilib -r t; exit $?'
This only works because of how perl's system/exec handle an argument with shell metacharacters in it (; in this case) and may break in the future if cover decides to quote it more rigirously. Also it shouldn't work under windows. I wish cover had a -prove option instead.
This one still generates coverage for *.t as well as CPAN modules at nonstandard locations. This behaviour can be fixed using +select/+ignore options (see the Devel::Cover's manpage):
cover -t +select ^lib +ignore ^
So the tl;dr "magic" command is
cover -t +select ^lib +ignore ^ -make 'prove -Ilib -r t; exit $?'
EDIT The following didn't work for me - it only prints short summary:
PERL5OPT="$PERL5OPT -MDevel::Cover" prove -Ilib -r t
cover -t +select ^lib +ignore ^
Note that prove -MSomething applies Something to prove itself and doesn't pass it on (unlike with -I).

Make prove run every test file with Devel::Cover activated:
$ prove --exec 'perl -MDevel::Cover=-silent,1 -Ilib' t/*.t
By default this will print the statistics after each test file. That’s why I added -silent => 1.
To print the complete statistics at the end add:
$ cover -summary

Related

why doesn't make -C change $PWD as seen through a scripting language such as Perl?

Here is temp/Makefile:
all:
echo $$PWD
echo $(CURDIR)
perl -e 'print $$ENV{"PWD"}'
and now
$make -C temp
make: Entering directory `/home/mgaleck/temp'
/home/mgaleck/temp
/home/mgaleck/temp
/home/mgaleck
make: Leaving directory `/home/mgaleck/temp'
Why is the third value without temp?
According to Make manual, -C option causes to "change the directory" (working directory?) first.
Same thing happens with Python.
Because the PWD environment variable doesn't hold the current working directory; it holds whatever the current working directory was the last time sh set it. Anything other than a shell starting up, or a shell executing the cd builtin (or a similar builtin like pushd, in shells that have it), has no effect on PWD, and relying on PWD anywhere except in the shell is probably a silly idea. Use getcwd (C), Cwd::getcwd (Perl), os.getcwd (Python), etc. instead.

Checking if a file is a text file without using -T?

Title is pretty self explanatory, are there file testing functions in perl or is there a built in module that allows file testing operations?
This is a non-issue as -T like all of the file test operators are perl builtins.
They are documented here: perldoc -X
-X FILEHANDLE
-X EXPR
-X DIRHANDLE
-X
A file test, where X is one of the letters listed below. This unary operator takes one argument, either a filename, a filehandle, or a dirhandle, and tests the associated file to see if something is true about it. If the argument is omitted, tests $_ , except for -t , which tests STDIN. Unless otherwise documented, it returns 1 for true and '' for false, or the undefined value if the file doesn't exist. Despite the funny names, precedence is the same as any other named unary operator.
...
-T File is an ASCII text file (heuristic guess).
-B File is a "binary" file (opposite of -T).
The "file test" functions available in Perl are part of the programming language itself. Based on what you're saying and from the comments on this page, it may be that you have been "asked not to use external commands" because someone thinks that the -T flag is relying on something that belongs to the underlying environment and not the Perl language.
-T is part of the -X file test unary operators which are inherent to Perl:
http://perldoc.perl.org/functions/-X.html
Underlying the -T operator (specifically) is the function pp_fttext, which lives in pp_sys.c. These are part of the underlying code that comprises Perl, and you can verify this by looking in the root directory of the Perl source distribution:
http://www.perl.org/get.html
It may be the only way to do what you were originally asking (how to do this without -T) might be to do what you were asked not to do (use something external to Perl to perform the test).

Error Packaging a Shell script with Autotools

I'm trying to write a simple Autotool package that just packages a single script. This might seem like overkill, but the script is to be added into the build-system for an embedded system and the build-system is designed to play nicely with Autotools.
I have a shell-script called wifi_query.sh. To package this I've followed the following steps:
Created Makefile.am which contains the following -
bin_SCRIPTS = wifi_query.sh
CLEANFILES = $(bin_SCRIPTS)
I also created wifi_query.sh.in which contains the line exec wifi_query.sh. I'm not sure I understand the purpose of the .in file.
I then run autoscan.
Then I run:
sed -e 's/FULL-PACKAGE-NAME/wifi_query/' \
-e 's/VERSION/1/' \
-e 's|BUG-REPORT-ADDRESS|/dev/null|' \
-e '10i\
AM_INIT_AUTOMAKE' \
< configure.scan > configure.ac
Run touch NEWS README AUTHORS ChangeLog.
Run autoreconf -iv
./configure
make distcheck
When I run make distcheck I get an error saying: "* No rule to make target 'wifi_query.sh', needed by 'all-am'. Stop.".
I don't understand this error, if anyone could give me any pointers that would be good. My suspicion is that the error may be due to wifi_query.sh.in, but I have very limited autotools experience.
It seems I needed to replace the line bin_SCRIPTS = wifi_query.sh with dist_bin_SCRIPTS = wifi_query.sh in Makefile.am. Having done that everything seems to work.

Devel::Cover with options for test coverage

In a project I am working on the directory layout that does not have a lib directory so we have
/X.pm
/X/Y.pm
...
/t/test.t
when I run
$ PERL5OPT=-MDevel::Cover make test
$ cover
I get report only for the files in t/
how can I tell Devel::Cover to report about all the files in the current directory except those in t?
I thought I can do it by this:
cover -t +inc . -inc t
but I get:
Unknown option: inc
Invalid command line options at /home/gabor/perl5/lib/perl5/x86_64-linux-thread-multi/Devel/Cover/Report/Html_minimal.pm line 677.
from the documentation it is unclear to me how can I supply these options.
cover doesn't actually generate coverage statistics, only reports on it IIRC.
Also, the +inc seems to need to be a part of PERL5OPT (comma separated to have -M pass them to import(), e.g. -MDevel::Cover=+inc,"/sometething")
I could be wrong - I only ever use Devel::Cover when actually running .t files, so never tried to do "all modules in directory" approach.

Why isn't this command taking the diff of two directories?

I am asked to diff two directories using Perl but I think something is wrong with my command,
$diff = system("sudo diff -r '/Volumes/$vol1' '/Volumes/$vol2\\ 1/' >> $diff.txt");
It doesn't display and output. Can someone help me with this? Thanks!
It seems that you want to store all differences in a string.
If this is the case, the command in the question is not going to work for a few reasons:
It's hard to tell whether it's intended or not, but the $diff variable is being used to set the filename storing the differences. Perhaps this should be diff.txt, not $diff.txt
The result of the diff command is saved in $diff.txt. It doesn't display anything in STDOUT. This can be remedied by omitting the >> $diff.txt part. If it also needs to be stored in file, consider the tee command:
sudo diff -r dir1/ dir2/ | tee diff.txt
When a system call is assigned to a variable, it will return 0 upon success. To quote the documentation:
The return value is the exit status of the program as returned by the wait call.
This means that $diff won't store the differences, but the command exit status. A more sensible approach would be to use backticks. Doing this will allow $diff to store whatever is output to STDOUT by the command:
my $diff = `sudo diff -r dir1/ dir2/ | tee diff.txt`; # Not $diff.txt
Is it a must to use the sudo command? Avoid using it if even remotely possible:
my $diff = `diff -r dir1/ dir2/ | tee diff.txt`; # Not $diff.txt
A final recommendation
Let a good CPAN module take care of this task, as backtick calls can only go so far. Some have already been suggested here; it may be well worth a look.
Is sudo diff being prompted for a password?
If possible, take out the sudo from the invocation of diff, and run your script with sudo.
"It doesn't display and output." -- this is becuase you are saving the differences to a file, and then (presumably) not doing anything with that resulting file.
However, I expect "diff two directories using Perl" does not mean "use system() to do it in the shell and then capture the results". Have you considered doing this in the language itself? For example, see Text::Diff. For more nuanced control over what constitutes a "difference", you can simply read in each file and craft your own algorithm to perform the comparisons and compile the similarities and differences.
You might want to check out Test::Differences for a more flexible diff implementation.