# compile_warnings.t - capture warnings during compilation time
# ----------------------------------------------------------------------
# If you're feeling lucky, run it across the whole codebase like this:
#   $ cd <your_branch_dir>/core
#   $ prove -lv t/compile_warnings.t :: ..
# ----------------------------------------------------------------------
# Explanation:
#   prove is a tool available where Perl is available. It runs tests
#   following Perl conventions.  When you need to pass parameters to
#   the test script (in this case: compile.t) then you need to
#   separate them from the parameters consumed by prove by two colons.
#   colon.  We pass the path to the parent directory, which is the
#   whole of trunk.
# Caveat:
# * This script has isn't perfect: If run on a complete branch, it
#   fails to detect dependencies within different extensions, e.g. if
#   FooPlugin depends on FooContrib, it will report a compilation
#   failure.
# * The script does only detect warnings which are available during
#   compile time.
# * Be aware that the result depends on the Perl
#   version used!
# ----------------------------------------------------------------------
# Copyright 2017 Harald.Joerg@arcor.de
# License: GPL V3
# ----------------------------------------------------------------------

use strict;
use warnings;

# ----------------------------------------------------------------------
# CGI::Carp, used by TWiki, captures (and thus hides) compilation
# warnings from the world. Therefore, prevent loading it by cheating
# about %INC
$INC{'CGI/Carp.pm'} = '/dev/null';

use Test::More;
use Test::Warnings qw(warnings :no_end_test);
use File::Find;

note "Running under Perl $]";

# Collect everything under the given path, defaults to current dir.
# The actual testing is done under check_compilation_warnings, see below.
my $path = ($ARGV[0] && -e $ARGV[0]) ? $ARGV[0] : '.';
find({wanted => \&check_compilation_warnings, no_chdir => 1},$path);

# Done!
done_testing;

# ----------------------------------------------------------------------
# Checking for warnings during the compilation phase can only be done
# if we postpone the compilation to runtime. "eval use" does this trick.
# ----------------------------------------------------------------------
sub check_compilation_warnings {
    my $file = $_;
    return unless $file =~ m!/lib.*\.pm$!;    # check only modules in lib
    return if     $file =~ m!/CPAN/!;         # skip CPAN imports
    return if  -l $file;                      # skip symlinks
    if ($file =~ m!^(.*?)/TWiki/(Plugins/|Contrib/)!) {
        eval "use lib '$1';";                 # add extension's lib
    }

    # convert file name to module name
    my $module = $file;
    $module =~ s!^.*lib/!!;
    $module =~ s!/!::!g;
    $module =~ s!\.pm!!;

    # now compile, using bareword syntax, and collect warnings
    my $missing_module;
    my @warnings = warnings {
        eval "use $module";
        if ($@) {
            # we'll skip tests which fail due to missing prerequisites
            $@ =~ m/Can't\s*locate\s*(\S+)\s*in|
                    Attempt\s*to\s*reload\s*(\S+)
                   /x;
            $missing_module = $1 || $2;
            if (! $missing_module) {
                # any other error makes the test case fail.
                diag$@;
                fail ("$file doesn't compile!");
            }
        }
    };

    # check the results
  SKIP: {
        skip "$module: '$missing_module' is not installed",1, if $missing_module;
        is(join("\n", @warnings),'',
           "$module compile time warnings:"
       );
    }
}

