1#!perl
2
3use strict;
4use warnings;
5
6# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.027
7
8use Test::More tests => 1;
9
10use ExtUtils::MakeMaker;
11use File::Spec;
12
13# from $version::LAX
14my $lax_version_re
15    = qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )?
16            |
17            (?:\.[0-9]+) (?:_[0-9]+)?
18        ) | (?:
19            v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )?
20            |
21            (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)?
22        )
23    )/x;
24
25# hide optional CPAN::Meta modules from prereq scanner
26# and check if they are available
27my $cpan_meta     = "CPAN::Meta";
28my $cpan_meta_pre = "CPAN::Meta::Prereqs";
29my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')"
30    && eval "require $cpan_meta_pre";    ## no critic
31
32# Verify requirements?
33my $DO_VERIFY_PREREQS = 1;
34
35sub _max {
36    my $max = shift;
37    $max = ( $_ > $max ) ? $_ : $max for @_;
38    return $max;
39}
40
41sub _merge_prereqs {
42    my ( $collector, $prereqs ) = @_;
43
44    # CPAN::Meta::Prereqs object
45    if ( ref $collector eq $cpan_meta_pre ) {
46        return $collector->with_merged_prereqs(
47            CPAN::Meta::Prereqs->new($prereqs) );
48    }
49
50    # Raw hashrefs
51    for my $phase ( keys %$prereqs ) {
52        for my $type ( keys %{ $prereqs->{$phase} } ) {
53            for my $module ( keys %{ $prereqs->{$phase}{$type} } ) {
54                $collector->{$phase}{$type}{$module}
55                    = $prereqs->{$phase}{$type}{$module};
56            }
57        }
58    }
59
60    return $collector;
61}
62
63my @include = qw(
64
65);
66
67my @exclude = qw(
68
69);
70
71# Add static prereqs to the included modules list
72my $static_prereqs = do './t/00-report-prereqs.dd';
73
74# Merge all prereqs (either with ::Prereqs or a hashref)
75my $full_prereqs
76    = _merge_prereqs( ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ),
77    $static_prereqs );
78
79# Add dynamic prereqs to the included modules list (if we can)
80my ($source) = grep {-f} 'MYMETA.json', 'MYMETA.yml';
81my $cpan_meta_error;
82if (   $source
83    && $HAS_CPAN_META
84    && ( my $meta = eval { CPAN::Meta->load_file($source) } ) )
85{
86    $full_prereqs = _merge_prereqs( $full_prereqs, $meta->prereqs );
87}
88else {
89    $cpan_meta_error = $@; # capture error from CPAN::Meta->load_file($source)
90    $source = 'static metadata';
91}
92
93my @full_reports;
94my @dep_errors;
95my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs;
96
97# Add static includes into a fake section
98for my $mod (@include) {
99    $req_hash->{other}{modules}{$mod} = 0;
100}
101
102for my $phase (qw(configure build test runtime develop other)) {
103    next unless $req_hash->{$phase};
104    next if ( $phase eq 'develop' and not $ENV{AUTHOR_TESTING} );
105
106    for my $type (qw(requires recommends suggests conflicts modules)) {
107        next unless $req_hash->{$phase}{$type};
108
109        my $title   = ucfirst($phase) . ' ' . ucfirst($type);
110        my @reports = [qw/Module Want Have/];
111
112        for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) {
113            next if $mod eq 'perl';
114            next if grep { $_ eq $mod } @exclude;
115
116            my $file = $mod;
117            $file =~ s{::}{/}g;
118            $file .= ".pm";
119            my ($prefix) = grep { -e File::Spec->catfile( $_, $file ) } @INC;
120
121            my $want = $req_hash->{$phase}{$type}{$mod};
122            $want = "undef" unless defined $want;
123            $want = "any" if !$want && $want == 0;
124
125            my $req_string
126                = $want eq 'any'
127                ? 'any version required'
128                : "version '$want' required";
129
130            if ($prefix) {
131                my $have = MM->parse_version(
132                    File::Spec->catfile( $prefix, $file ) );
133                $have = "undef" unless defined $have;
134                push @reports, [ $mod, $want, $have ];
135
136                if (   $DO_VERIFY_PREREQS
137                    && $HAS_CPAN_META
138                    && $type eq 'requires' )
139                {
140                    if ( $have !~ /\A$lax_version_re\z/ ) {
141                        push @dep_errors,
142                            "$mod version '$have' cannot be parsed ($req_string)";
143                    }
144                    elsif ( !$full_prereqs->requirements_for( $phase, $type )
145                        ->accepts_module( $mod => $have ) )
146                    {
147                        push @dep_errors,
148                            "$mod version '$have' is not in required range '$want'";
149                    }
150                }
151            }
152            else {
153                push @reports, [ $mod, $want, "missing" ];
154
155                if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) {
156                    push @dep_errors, "$mod is not installed ($req_string)";
157                }
158            }
159        }
160
161        if (@reports) {
162            push @full_reports, "=== $title ===\n\n";
163
164            my $ml = _max( map { length $_->[0] } @reports );
165            my $wl = _max( map { length $_->[1] } @reports );
166            my $hl = _max( map { length $_->[2] } @reports );
167
168            if ( $type eq 'modules' ) {
169                splice @reports, 1, 0, [ "-" x $ml, "", "-" x $hl ];
170                push @full_reports, map {
171                    sprintf( "    %*s %*s\n", -$ml, $_->[0], $hl, $_->[2] )
172                } @reports;
173            }
174            else {
175                splice @reports, 1, 0, [ "-" x $ml, "-" x $wl, "-" x $hl ];
176                push @full_reports, map {
177                    sprintf( "    %*s %*s %*s\n",
178                        -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2] )
179                } @reports;
180            }
181
182            push @full_reports, "\n";
183        }
184    }
185}
186
187if (@full_reports) {
188    diag
189        "\nVersions for all modules listed in $source (including optional ones):\n\n",
190        @full_reports;
191}
192
193if ( $cpan_meta_error || @dep_errors ) {
194    diag
195        "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n";
196}
197
198if ($cpan_meta_error) {
199    my ($orig_source) = grep {-f} 'MYMETA.json', 'MYMETA.yml';
200    diag
201        "\nCPAN::Meta->load_file('$orig_source') failed with: $cpan_meta_error\n";
202}
203
204if (@dep_errors) {
205    diag join( "\n",
206        "\nThe following REQUIRED prerequisites were not satisfied:\n",
207        @dep_errors, "\n" );
208}
209
210pass;
211
212# vim: ts=4 sts=4 sw=4 et:
213