#! /usr/bin/perl
#
# This script extracts information from files produced by gcov showing what
# parts of each file have *not* been executed by the test programs.
# 
# To create a coverage report, use the following steps:
#
# configure --enable-coverage <other options>
# make 
# make install
# make testing
# < run other tests, such as the Intel, MPICH1, and C++ tests >
# make coverage
# maint/getcoverage src/mpi src/util > coverage.txt
#
# The script in mpich2-tests/getcoverage will perform all of these steps 
# (this script is not yet included with the MPICH2 distribution)
#
#
$includeFileInOutput = 0;
$skipErrExits = 1;
$outputUncovered = 1;
@UnCalled = ();
for (@ARGV) {
    my $filename = $_;
    if (-d $filename) {
	@files = &ExpandDir( $filename );
	foreach $file (@files) {
	    $missed_lines = &CountUncoveredLines( $file );
	    if ($missed_lines) {
		print "$missed_lines line(s) not covered by tests in $file\n";
	    }
	    else {
		print "All code covered by tests in $file\n";
	    }
	}
    }
    elsif (-s $filename) {
	$missed_lines = &CountUncoveredLines( $filename );
	if ($missed_lines) {
	    print "$missed_lines line(s) not covered by tests in $filename\n";
	}
	else {
	    print "All code covered by tests in $filename\n";
	}
    }
    else {
	print "Cannot open $filename\n";
    }
}

for $routine (@UnCalled) {
    print STDERR "$routine never called\n";
}

sub CountUncoveredLines {
    my $filename = $_[0];
    my $missed_lines = 0;
    my $headerOutput = 0;
    my $linecount = 0;
    my $lastLineOut = -1;
    my $oldLine;
    my $lastLine;

    open( FD, "<$filename" ) || die "Could not open $filename\n";

    # Note that linecount is relative to the foo.c.gcov file, not the
    # original foo.c file.
    while (<FD>) {
	$linecount++;
	# Skip any error checking block
	if (/^\s*#\s*ifdef\s+HAVE_ERROR_CHECKING/) {
	    while (<FD>) {
		$linecount++;
		if (/^\s*#\s*endif/ || /^\s*#\s*els/) { 
		    last; 
		}
	    }
	    next;	       
	}
	# If requested, skip obvious error checking lines
	if ($skipErrExits && 
	    (/FUNC_EXIT.*STATE/ || /MPIR_Err_return_/ || 
	     /MPIR_Err_create_code/)) {
	    next;
	}
	if (/^\s*######/) {
	    if (! /^\s*######\s*\}\s*/) {
		$missed_lines++;
		
		# The char\s+.* allows char or const char (or other 
		# things, but nothing else should use FCNAME).
		if (/static\s+char\s+.*FCNAME\[\]\s*=\s*\"(.*)\"/) {
		    # Add this to a list of functions never called.
		    $UnCalled[$#UnCalled + 1] = $1;
		}
		if ($outputUncovered) {
		    if (!$headerOutput) {
			print "\nUncovered lines in $filename\n";
			$headerOutput = 1;
		    }
		    if ($lastLineOut < $linecount - 2) {
			my $ll = $linecount - 2;
			print "$ll:\t$oldLine";
		    }
		    if ($lastLineOut < $linecount - 1) {
			my $ll = $linecount - 1;
			print "$ll:\t$lastLine";
		    }
		    print "$linecount:\t$_";
		    $lastLineOut = $linecount;
		}
	    }
	}
	if ($includeFileInOutput) {
	    print $_;
	}
	$oldLine = $lastLine;
	$lastLine = $_;
    }
    close (FD);
    return $missed_lines;
}

# Get all of the .gcov files from the named directory, including any subdirs
sub ExpandDir {
    my $dir = $_[0];
    my @otherdirs = ();
    my @files = ();
    opendir DIR, "$dir";
    while ($filename = readdir DIR) {
	if ($filename =~ /^\./ || $filename eq "CVS") {
	    next;
	}
	elsif (-d "$dir/$filename") {
	    $otherdirs[$#otherdirs+1] = "$dir/$filename";
	}
	elsif ($filename =~ /(.*\.gcov)$/) {
	    $files[$#files + 1] = "$dir/$filename";
	}
    }
    closedir DIR;
    # (almost) tail recurse on otherdirs (we've closed the directory handle,
    # so we don't need to worry about it anymore)
    foreach $dir (@otherdirs) {
	@files = (@files, &ExpandDir( $dir ) );
    }
    return @files;
}

#
# To generate a summary
# cd mpich2/src 
# ~/projects/mpich2/maint/getcoverage mpi/*/*.gcov mpi/romio/mpi-io/*.gcov \
# mpi/romio/adio/ad_nfs/*.gcov mpi/romio/adio/ad_ufs/*.gcov \
# util/info/*.gcov \
# mpid/ch3/src/*.gcov mpid/ch3/channels/sock/src/*.gcov > coverage.txt

# Now can use
# maint/getcoverage src/mpi src/util/info >coveragebase.txt
# maint/getcoverage src/mpid/ch3/src/*.gcov \
#  src/mpid/ch3/channels/sock/src/*.gcov > coveragempid.txt
