#!perl
#
# Test to ensure that no boilerplate text generated by Module::Starter::Plugin::MyGuts
# is left in the distribution files.
#
# NOTE:
#   To see verbose output in correct order, use yath or run:
#     prove -l xt/boilerplate.t --merge -v

use v5.42.0;

use strict;
use warnings;

use Test2::V1 qw<
    note
    diag
    pass
    fail
>;

use re qw< eval >;
#use DDP output => 'stdout';

sub not_in_file_ok
{
    my $filename = shift;

    note("FILENAME: $filename\n\n");

    open my $fh, '<', $filename or die "Failed to open $filename for reading: $!";
    my $file = do { local $/ = undef; <$fh> };  # Slurp entire file.
    close $fh or die $!;

    my $desc;
    my @regex_type;

    my @readme_rgx = (
        'The\ README\ is\ used\ to\ introduce\ the\ module\ and\ provide\ instructions\ on\
how\ to\ install\ the\ module\,\ any\ machine\ dependencies\ it\ may\ have\ \(for\
example\ C\ compilers\ and\ installed\ libraries\)\ and\ any\ other\ information\
that\ should\ be\ provided\ before\ the\ module\ is\ installed\.\
\
A\ README\ file\ is\ required\ for\ CPAN\ modules\ since\ CPAN\ extracts\ the\ README\
file\ from\ a\ module\ distribution\ so\ that\ people\ browsing\ the\ archive\
can\ use\ it\ to\ get\ an\ idea\ of\ the\ module\'s\ uses\.\ It\ is\ usually\ a\ good\ idea\
to\ provide\ version\ information\ here\ so\ that\ people\ can\ decide\ whether\
fixes\ for\ the\ module\ are\ worth\ downloading\.\
(?{ $desc = "introduction" })',
    );

    my @changes_rgx = (
        'v1\.0\.0\ \ \ \ YYYY\-MM\-DD\ HH\:MM\:SSZ\
\ \ \ \ \ \ \ \ \ \ \-\ Initial\ release\
(?{ $desc = "changelog" })',
    );

    my @modules_rgx = (
        'sub\ function1\ \(\)\
\{\
\}\
(?{ $desc = "stub function1 definition" })',
        'sub\ function2\ \(\)\
\{\
\}\
(?{ $desc = "stub function2 definition" })',
        '[^ \n]+ - new\ abstract(?{ $desc = "POD NAME" })',
        'Quick\ summary\ of\ what\ the\ module\ does\.\
\
With\ brief\ examples\:\
\
\ \ \ \ \#\ Procedural\
\
\ \ \ \ use\ App\:\:cpan2arch\ qw\<\ function\ \>\;\
\
\ \ \ \ my\ \$foo\ \=\ function\(\.\.\.\)\;\
\ \ \ \ \.\.\.\
\
\ \ \ \ \#\ OOP\
\
\ \ \ \ use\ App\:\:cpan2arch\;\
\
\ \ \ \ my\ \$foo\ \=\ App\:\:cpan2arch\-\>new\;\
\ \ \ \ \$foo\-\>method\(\.\.\.\)\;\
\ \ \ \ \.\.\.\
(?{ $desc = "POD SYNOPSIS" })',
        'Overview\ or\ extended\ description\ and\ discussion\ of\ the\ module\.(?{ $desc = "POD DESCRIPTION" })',
        'A\ list\ of\ functions\ that\ can\ be\ exported\.\ Delete\ this\ section\ if\ nothing\ is\
exported\,\ such\ as\ for\ a\ purely\ object\-oriented\ module\.\
(?{ $desc = "POD EXPORTS" })',
        '\=head2\ function1\
\
\=head2\ function2\
(?{ $desc = "POD SUBROUTINES/METHODS" })',
        '\=over\ 4\
\
\=item\ \*\
\
L\<Some\:\:Module\>\
\
\=item\ \*\
\
L\<https\:\/\/some\-reference\.TLD\>\
\
\=back\
(?{ $desc = "POD SEE ALSO" })',
    );

    foreach ($filename) {
        if    (/\AREADME\z/)  { push @regex_type, @readme_rgx }
        elsif (/\AChanges\z/) { push @regex_type, @changes_rgx }
        elsif (/\.pm\z/)      { push @regex_type, @modules_rgx }
        else                  { die "$filename is not supported" }
    }

    #p @regex_type;
    #note("\n");

    # Concat and compile the regexes.
    my $joined = join '|', @regex_type;
    my $regex  = qr{^(?> $joined )}mx;

    #note("REGEX:\n");
    #p $regex;
    #note("\n");

    my $c = 0;

    # Scan the file with its respective regex type.
    while (1) {
        # Boilerplate
        if ( $file =~ /\G$regex/gc ) {
            my $end = '';
            ++$c;

            note("MATCH:\n$c '$&'\n");
            fail("$filename contains $desc boilerplate text");

            # Count lines of a multiline match.
            my $nl = $& =~ tr{\n}{};
            if ( $nl > 1 ) {
                $nl  += $c - 1;
                $end  = ',' . $nl;
            }

            diag("$desc appears on lines ${c}$end");
            note("\n");

            $c = $nl;
        }
        # Generic line (forwards scanner line-by-line).
        elsif ( $file =~ /\G([^\n]*+)\n/gc ) {
            ++$c;
            #note("$c '$1'");
        }

        # End of file.
        if ( $file =~ /\G\z/ ) {
            pass("$filename contains no boilerplate text") unless defined $desc;
            note("\n");

            last;
        }
    }
}

not_in_file_ok('README');
not_in_file_ok('Changes');
not_in_file_ok('lib/App/cpan2arch.pm');

T2->done_testing;
