# New Ticket Created by James Keenan # Please include the string: [perl #42072] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=42072 >
Fellow Parrot hackers: 1. Back in November and December, when I was refactoring tools/build/ pmc2c.pl into lib/Parrot/Pmc2c/Utils.pm, I tried to write tests for everyone of the command-line options documented in the POD. I experienced problems writing a test for the 'no-body' option, made a mental note to get back to it, but never did. Consequently, code in Utils.pm which depends on the 'no-body' option is not completely covered by the test suite. This weakness is now having an impact on other lines of code which have been added as tewk, jonathan and others work on Parrot::Pmc2c::PCCMETHOD and other modules. So I'm trying to find out how to use the 'no-body' option ... and also trying to find out whether anyone ever uses this option. 2. Here is how the 'no-body' option is documented in the POD (which I carried over almost verbatim from earlier versions of tools/build/ pmc2c.pl): =item C<--no-body> Emit an empty body in the dump. This may be useful for debugging. That's it. Since it's meant for debugging, it quite logically never appears in any of the 169+ calls to pmc2c.pl invoked by 'make'. 3. Calling 'no-body' on the command-line internally sets $opt {nobody}. This variable is used exactly once inside lib/Parrot/Pmc2c/ Utils.pm, deep inside parse_pmc(): $methodblock = "" if $opt->{nobody}; # line 672 Since I never wrote a test for this option, the case where $opt-> {nobody} was true and where, therefore, $methodblock evaluated to false was never covered by the test suite. (See http:// thenceforward.net/parrot/coverage/pmc2c/lib-Parrot-Pmc2c-Utils- pm.html and http://thenceforward.net/parrot/coverage/pmc2c/lib-Parrot- Pmc2c-Utils-pm--branch.html#L672.) 4. I lived with this lack of coverage for several months, but new code has been added to Parrot::Pmc2c::Utils which asks whether $methodblock is true or false: if ( $methodblock and $methodblock =~ /PCCINVOKE/ ) { # line 689 $flags_ref->{need_fia_header} = 1; } Now I have an uncovered condition as well as an uncovered branch. (See http://thenceforward.net/parrot/coverage/pmc2c/lib-Parrot-Pmc2c- Utils-pm--condition.html#L689.) 5. "Alright," you're thinking, "why don't you go ahead and actually call the no-body option and see what happens?" I did so. I first wrote a test which was similar to those found in t/tools/pmc2cutils/ 05-gen_c.t. It is attached as 08-nobody.t. An excerpt of its output when run with 'prove -v' is attached as output-08- nobody.excerpt.txt. The relevant output is the following: substr outside of string at /Users/jimk/work/parrot/lib/Parrot/ Pmc2c.pm line 534. Use of uninitialized value in substitution (s///) at /Users/jimk/ work/parrot/lib/Parrot/Pmc2c.pm line 536. Use of uninitialized value in concatenation (.) or string at / Users/jimk/work/parrot/lib/Parrot/Pmc2c.pm line 578. ... which occurs a total of 45 times. The fact that I am getting warnings causes the final test in 08-nobody.t to fail. It's always a PITA when a bug in your code manifests itself as a series of warnings from some other code which you have not modified in the least. 6. Here are the relevant sections of lib/Parrot/Pmc2c.pm: my $total_body; # <-- line 523 if ( $method->{loc} eq 'vtable' ) { $total_body = rewrite_vtable_method( $classname, $meth, $super, $self->{super}, $body ); } else { $total_body = rewrite_nci_method( $classname, $meth, $body ); } Parrot::Pmc2c::PCCMETHOD::rewrite_pccinvoke( $method, \ $total_body ); # now split into MMD if necessary: my $additional_bodies = ''; $total_body = substr $total_body, 1, -1; # <-- line 534 my $standard_body = $total_body; while ( $total_body =~ s/\bMMD_(\w+):\s*// ) { # # <-- line 536 my $right_type = $1; my $body_part = extract_bracketed( $total_body, '{' ); die "Empty MMD body near '$total_body'" if ( !$body_part ); $body_part = substr( $body_part, 1, -1 ); $body_part =~ s/\n(\s*)$//s; [snip approx. 20 lines] } $cout .= $self->decl( $classname, $method, 0 ); if ( exists $method->{pre_block} ) { $cout .= $method->{pre_block}; # This is the part that comes from the PMC file. $cout .= $self->line_directive( $method->{line}, $self-> {file} ); $cout .= $standard_body; $cout .= $method->{post_block}; $cout .= "\n}\n"; } else { # This is the part that comes from the PMC file. $cout .= $self->line_directive( $method->{line}, $self-> {file} ); $cout .= "{$standard_body\n}\n"; # <-- line 578 } So when the 'no-body' option is set in tools/build/pmc2c.pl, variable $total_body in lib/Parrot/Pmc2c.pm, not surprisingly, is uninitialized and messy warnings are thrown. 7. 08-nobody.t, like all the tests in t/tools/pmc2cutils/, creates all its test files in temporary directories and cleans up after itself. I created a Perl script parallel to this test file without all the tempdirs so that I could look at the files produced. That script is attached as 'nobody.pl'. If you run it, you will see that when called with --no-body, it throws the same warnings as 08-nobody.t. 8. Which leaves me with these questions: a. If an option intended for debugging throws a lot of warnings when run, what use is it for debugging? b. Is anybody using the --no-body option in Parrot development? If not, should I eliminate it? c. If someone *is* using the --no-body option, how do you deal with all the warnings? kid51
08-nobody.t
Description: Binary data
[parrot] 506 $ prove -v t/tools/pmc2cutils/08-nobody.t t/tools/pmc2cutils/08-nobody.... OK: Parrot top directory located ok 1 - use Parrot::Pmc2c::Utils; ok 2 - use Cwd; ok 3 - use File::Temp; ok 4 - changed to temp directory for testing ok 5 - created src/ under tempdir ok 6 - created src/pmc/ under tempdir ok 7 - all src/pmc/*.pmc files copied to tempdir ok 8 - The object isa Parrot::Pmc2c::Utils ok 9 - dump_vtable created vtable.dump ok 10 - dump_pmc succeeded ok 11 - default.dump created as expected substr outside of string at /Users/jimk/work/parrot/lib/Parrot/Pmc2c.pm line 534. Use of uninitialized value in substitution (s///) at /Users/jimk/work/parrot/lib/Parrot/Pmc2c.pm line 536. Use of uninitialized value in concatenation (.) or string at /Users/jimk/work/parrot/lib/Parrot/Pmc2c.pm line 578. [3 error messages above repeat a total of 45 times.] not ok 13 - no-body option worked # Failed test (t/tools/pmc2cutils/08-nobody.t at line 84) # undef # doesn't match '(?-xism:src/pmc/default\.pmc)' ok 14 - changed back to original directory ok 15 - Completed all tests in t/tools/pmc2cutils/08-nobody.t 1..15 # Looks like you failed 1 test of 15. dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 13 Failed 1/15 tests, 93.33% okay Failed Test Stat Wstat Total Fail List of Failed ------------------------------------------------------------------------------- t/tools/pmc2cutils/08-nobody.t 1 256 15 1 13 Failed 1/1 test scripts. 1/15 subtests failed. Files=1, Tests=15, 3 wallclock secs ( 0.84 cusr + 0.28 csys = 1.12 CPU) Failed 1/1 test programs. 1/15 subtests failed.
#! perl # Copyright (C) 2006, The Perl Foundation. # nobody.pl use strict; use warnings; use File::Basename; use File::Copy; use Data::Dumper; use Carp; use Cwd; use Getopt::Long; my ($topdir, $tdir, $nobody, $usage); GetOptions( "topdir=s" => \$topdir, "tdir=s" => \$tdir, "no-body" => \$nobody, "help" => \$usage, ); Usage() if $usage; croak "Must supply path to top directory in your sandbox" unless -d $topdir; croak "Must supply path to a temporary directory" unless -d $tdir; my $libdir = qq{$topdir/lib}; unshift @INC, $libdir; require Parrot::Pmc2c::Utils; my ( %opt, @include, @args ); my $dump_file; my $self; my $cwd = cwd(); my @include_orig = ( qq{$topdir}, qq{$topdir/src/pmc}, ); chdir $tdir; mkdir qq{$tdir/src} unless -d qq{$tdir/src}; my $temppmcdir = qq{$tdir/src/pmc}; mkdir $temppmcdir unless -d $temppmcdir; croak "Failed to create $temppmcdir" unless -d $temppmcdir; my @pmcfiles = ( "$topdir/src/pmc/default.pmc", "$topdir/src/pmc/array.pmc", ); my $pmcfilecount = scalar(@pmcfiles); my $copycount; foreach my $pmcfile (@pmcfiles) { my $basename = basename($pmcfile); my $rv = copy( $pmcfile, qq{$temppmcdir/$basename} ); $copycount++ if $rv; } @include = ( $tdir, $temppmcdir, @include_orig ); @args = ( qq{$temppmcdir/default.pmc}, ); if ($nobody) { %opt = ( nobody => 1 ); } $self = Parrot::Pmc2c::Utils->new( { include => [EMAIL PROTECTED], opt => \%opt, args => [EMAIL PROTECTED], } ); $dump_file = $self->dump_vtable("$topdir/vtable.tbl"); croak "Unable to create vtable.dump" unless -e $dump_file; $self->dump_pmc(); croak "Unable to create default.dump" unless -f qq{$temppmcdir/default.dump}; my ( $fh, $msg, $rv ); { my $currfh = select($fh); open( $fh, '>', \$msg ) or die "Unable to open handle: $!"; $rv = $self->gen_c(); select($currfh); } croak "gen_c failed" unless $rv; if (defined $msg) { print STDERR "This is the message:\n", $msg, "\n"; } chdir $cwd; sub Usage { print "Usage:\n"; print " perl $0 --topdir=/path/to/sandbox --tdir=/path/to/tempdir [--no-body]\n\n"; exit 0; }