File: 55namespaces_cleaned.t

package info (click to toggle)
libdbix-class-perl 0.082844-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,320 kB
  • sloc: perl: 27,215; sql: 322; sh: 29; makefile: 16
file content (227 lines) | stat: -rw-r--r-- 6,168 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
BEGIN {
  if ($] < 5.010) {

    # Pre-5.10 perls pollute %INC on unsuccesfull module
    # require, making it appear as if the module is already
    # loaded on subsequent require()s
    # Can't seem to find the exact RT/perldelta entry
    #
    # The reason we can't just use a sane, clean loader, is because
    # if a Module require()s another module the %INC will still
    # get filled with crap and we are back to square one. A global
    # fix is really the only way for this test, as we try to load
    # each available module separately, and have no control (nor
    # knowledge) over their common dependencies.
    #
    # we want to do this here, in the very beginning, before even
    # warnings/strict are loaded

    unshift @INC, 't/lib';
    require DBICTest::Util::OverrideRequire;

    DBICTest::Util::OverrideRequire::override_global_require( sub {
      my $res = eval { $_[0]->() };
      if ($@ ne '') {
        delete $INC{$_[1]};
        die $@;
      }
      return $res;
    } );
  }
}

use strict;
use warnings;

# FIXME This is a crock of shit, needs to go away
# currently here to work around https://rt.cpan.org/Ticket/Display.html?id=74151
# kill with fire when PS::XS / RT#74151 is *finally* fixed
BEGIN {
  my $PS_provider;

  if ( "$]" < 5.010 ) {
    require Package::Stash::PP;
    $PS_provider = 'Package::Stash::PP';
  }
  else {
    require Package::Stash;
    $PS_provider = 'Package::Stash';
  }
  eval <<"EOS" or die $@;

sub stash_for (\$) {
  $PS_provider->new(\$_[0]);
}
1;
EOS
}

use Test::More;

use lib 't/lib';

BEGIN {
  require DBICTest::RunMode;
  plan( skip_all => "Skipping test on plain module install" )
    if DBICTest::RunMode->is_plain;
}

use DBICTest;
use File::Find;
use File::Spec;
use B qw/svref_2object/;

# makes sure we can load at least something
use DBIx::Class;
use DBIx::Class::Carp;

my @modules = grep {
  my ($mod) = $_ =~ /(.+)/;

  # not all modules are loadable at all times
  do {
    # trap deprecation warnings and whatnot
    local $SIG{__WARN__} = sub {};
    eval "require $mod";
  } ? $mod : do {
    SKIP: { skip "Failed require of $mod: " . ($@ =~ /^(.+?)$/m)[0], 1 };
    (); # empty RV for @modules
  };

} find_modules();

# have an exception table for old and/or weird code we are not sure
# we *want* to clean in the first place
my $skip_idx = { map { $_ => 1 } (
  (grep { /^DBIx::Class::CDBICompat/ } @modules), # too crufty to touch
  'SQL::Translator::Producer::DBIx::Class::File', # ditto

  # not sure how to handle type libraries
  'DBIx::Class::Storage::DBI::Replicated::Types',
  'DBIx::Class::Admin::Types',

  # G::L::D is unclean, but we never inherit from it
  'DBIx::Class::Admin::Descriptive',
  'DBIx::Class::Admin::Usage',

  # utility classes, not part of the inheritance chain
  'DBIx::Class::ResultSource::RowParser::Util',
  'DBIx::Class::_Util',
) };

my $has_moose = eval { require Moose::Util };

# can't use Class::Inspector for the mundane parts as it does not
# distinguish imports from anything else, what a crock of...
# Moose is not always available either - hence just do it ourselves

my $seen; #inheritance means we will see the same method multiple times

for my $mod (@modules) {
  SKIP: {
    skip "$mod exempt from namespace checks",1 if $skip_idx->{$mod};

    my %all_method_like = (map
      { %{stash_for($_)->get_all_symbols('CODE')} }
      (reverse @{mro::get_linear_isa($mod)})
    );

    my %parents = map { $_ => 1 } @{mro::get_linear_isa($mod)};

    my %roles;
    if ($has_moose and my $mc = Moose::Util::find_meta($mod)) {
      if ($mc->can('calculate_all_roles_with_inheritance')) {
        $roles{$_->name} = 1 for ($mc->calculate_all_roles_with_inheritance);
      }
    }

    for my $name (keys %all_method_like) {

      # overload is a funky thing - it is not cleaned, and its imports are named funny
      next if $name =~ /^\(/;

      my $gv = svref_2object($all_method_like{$name})->GV;
      my $origin = $gv->STASH->NAME;

      is ($gv->NAME, $name, "Properly named $name method at $origin" . ($origin eq $mod
        ? ''
        : " (inherited by $mod)"
      ));

      next if $seen->{"${origin}:${name}"}++;

      if ($origin eq $mod) {
        pass ("$name is a native $mod method");
      }
      elsif ($roles{$origin}) {
        pass ("${mod}::${name} came from consumption of role $origin");
      }
      elsif ($parents{$origin}) {
        pass ("${mod}::${name} came from proper parent-class $origin");
      }
      else {
        my $via;
        for (reverse @{mro::get_linear_isa($mod)} ) {
          if ( ($_->can($name)||'') eq $all_method_like{$name} ) {
            $via = $_;
            last;
          }
        }

        # exception time
        if (
          ( $name eq 'import' and $via = 'Exporter' )
        ) {
          pass("${mod}::${name} is a valid uncleaned import from ${name}");
        }
        else {
          fail ("${mod}::${name} appears to have entered inheritance chain by import into "
              . ($via || 'UNKNOWN')
          );
        }
      }
    }

    # some common import names (these should never ever be methods)
    for my $f (qw/carp carp_once carp_unique croak confess cluck try catch finally/) {
      if ($mod->can($f)) {
        my $via;
        for (reverse @{mro::get_linear_isa($mod)} ) {
          if ( ($_->can($f)||'') eq $all_method_like{$f} ) {
            $via = $_;
            last;
          }
        }
        fail ("Import $f leaked into method list of ${mod}, appears to have entered inheritance chain at "
            . ($via || 'UNKNOWN')
        );
      }
      else {
        pass ("Import $f not leaked into method list of $mod");
      }
    }
  }
}

sub find_modules {
  my @modules;

  find( {
    wanted => sub {
      -f $_ or return;
      s/\.pm$// or return;
      s/^ (?: lib | blib . (?:lib|arch) ) . //x;
      push @modules, join ('::', File::Spec->splitdir($_));
    },
    no_chdir => 1,
  }, (
    # find them in both lib and blib, duplicates are fine, since
    # @INC is preadjusted for us by the harness
    'lib',
    ( -e 'blib' ? 'blib' : () ),
  ));

  return sort @modules;
}

done_testing;