1use strict; 2use warnings; 3 4use English qw(-no_match_vars); 5use Carp qw(confess); 6 7use B::Keywords qw(); 8use List::MoreUtils qw< apply uniq >; 9 10my $this_program = __FILE__; 11(my $test_file_name = $this_program) =~ s/[.]PL\Z/.t/ms; 12if ($this_program eq $test_file_name) { 13 confess 14 'Was not able to figure out the name of the file to generate.' 15 . "This program: $this_program."; 16} 17 18print "\n\nGenerating $test_file_name.\n"; 19 20my @globals = ( 21 @B::Keywords::Arrays, 22 @B::Keywords::Hashes, 23 @B::Keywords::Scalars, 24); 25push @globals, uniq apply { s/ \A ([^*]) /*$1/xms } @B::Keywords::Filehandles; 26my %exemptions = map {$_ => 1} qw( 27 $_ 28 $ARG 29 @_ 30); 31 32my $carat_re = qr/\A [\$%]\^\w+ /xms; 33 34my $numvars = @globals - keys %exemptions; 35my $numcarats = grep {!$exemptions{$_} && m/ $carat_re /xms} @globals; 36 37open my $test_file, '>', $test_file_name 38 or confess "Could not open $test_file_name: $ERRNO"; 39 40print_header($test_file); 41print_pass_local($test_file, \@globals); 42print_pass_local_deref($test_file, \@globals); 43print_pass_non_local_exception($test_file, \@globals); 44print_fail_non_local($test_file, \@globals, $numvars, $numcarats); 45print_fail_non_local_deref($test_file, \@globals); 46print_footer($test_file); 47 48close $test_file 49 or confess "Could not close $test_file_name: $ERRNO"; 50 51print "Done.\n\n"; 52 53sub print_header { 54 my ($test_file) = @_; 55 56 print {$test_file} "# DO NOT EDIT!!! This test suite generated by $this_program\n"; 57 print {$test_file} <<'END_CODE'; 58 59use strict; 60use warnings; 61use Perl::Lint::Policy::Variables::RequireLocalizedPunctuationVars; 62use t::Policy::Util qw/fetch_violations/; 63use Test::Base::Less; 64 65my $class_name = 'Variables::RequireLocalizedPunctuationVars'; 66 67filters { 68 params => [qw/eval/], # TODO wrong! 69}; 70 71for my $block (blocks) { 72 my $violations = fetch_violations($class_name, $block->input, $block->params); 73 is scalar @$violations, $block->failures, $block->dscr; 74} 75 76done_testing; 77 78__DATA__ 79 80=== 81--- dscr: Named magic variables, special case passes 82--- failures: 0 83--- params: 84--- input 85local ($_, $RS) = (); 86local $SIG{__DIE__} = sub { print "AAAAAAARRRRRGGGGHHHHH....\n"; }; 87$_ = 1; 88$ARG = 1; 89@_ = (1, 2, 3); 90END_CODE 91 92 return; 93} 94 95sub print_pass_local { 96 my ($test_file, $globals) = @_; 97 98 print {$test_file} <<'END_CODE'; 99 100=== 101--- dscr: Named magic variables, pass local 102--- failures: 0 103--- params: 104--- input 105END_CODE 106 107 for my $varname (@{$globals}) { 108 print {$test_file} "local $varname = ();\n"; 109 } 110 111 print {$test_file} <<"END_CODE"; 112 113=== 114--- dscr: Named magic variables, pass local() 115--- failures: 0 116--- params: 117--- input 118END_CODE 119 120 for my $varname (@{$globals}) { 121 print {$test_file} "local ($varname) = ();\n"; 122 } 123 124 print {$test_file} <<"END_CODE"; 125 126=== 127--- dscr: Named magic variables, pass (local) 128--- failures: 0 129--- params: 130--- input 131END_CODE 132 133 for my $varname (@{$globals}) { 134 print {$test_file} "(local $varname) = ();\n"; 135 } 136 137 print {$test_file} <<"END_CODE"; 138 139=== 140--- dscr: Named magic variables, pass = (local) = 141--- failures: 0 142--- params: 143--- input 144END_CODE 145 146 for my $varname (@{$globals}) { 147 print {$test_file} "\@foo = (local $varname) = ();\n"; 148 } 149 150 return; 151} 152 153 154sub print_pass_local_deref { 155 my ($test_file, $globals) = @_; 156 157 my %subscript = ( 158 '%' => '{foo}', 159 '@' => '[0]', 160 ); 161 162 my @derefs = grep { $subscript{substr $_, 0, 1} } @{ $globals }; 163 164 print {$test_file} <<"END_CODE"; 165 166=== 167--- dscr: Named magic variables, pass local dereferenced 168--- failures: 0 169--- params: 170--- input 171END_CODE 172 173 foreach my $varname ( @derefs ) { 174 my ($sigil, $barename) = $varname =~ m/ (.)(.*) /smx; 175 print {$test_file} 'local $', $barename, 176 $subscript{$sigil}, " = 'bar';\n"; 177 } 178 179} 180 181 182sub print_pass_non_local_exception { 183 my ($test_file, $globals) = @_; 184 185 (my $except = "@$globals") =~ s< ([\\']) ><\\$1>gmsx; 186 print {$test_file} <<"END_CODE"; 187 188=== 189--- dscr: Named magic variables, pass non-local but in exception list 190--- failures: 0 191--- params: {require_localized_punctuation_vars => {allow => '$except'}} 192--- input 193END_CODE 194 195 foreach my $varname (@{$globals}) { 196 next if $exemptions{$varname}; 197 print {$test_file} "$varname = ();\n"; 198 } 199} 200 201 202sub print_fail_non_local { 203 my ($test_file, $globals, $numvars, $numcarats) = @_; 204 205 print {$test_file} <<"END_CODE"; 206 207=== 208--- dscr: Named magic variables, fail non-local, non-carats 209--- failures: @{[$numvars - $numcarats]} 210--- params: 211--- input 212END_CODE 213 214 for my $varname (@{$globals}) { 215 next if $exemptions{$varname}; 216 next if $varname =~ m/ $carat_re /xms; 217 print {$test_file} "$varname = ();\n"; 218 } 219 220 print {$test_file} <<"END_CODE"; 221 222=== 223--- dscr: Named magic variables, fail non-local, carats 224--- failures: $numcarats 225--- params: 226--- input 227END_CODE 228 229 for my $varname (@{$globals}) { 230 next if $exemptions{$varname}; 231 next if $varname !~ m/ $carat_re /xms; 232 print {$test_file} "$varname = ();\n"; 233 } 234 235 print {$test_file} <<"END_CODE"; 236 237=== 238--- dscr: Named magic variables, fail non-local, carats, no space 239--- failures: $numcarats 240--- params: 241--- input 242END_CODE 243 244 for my $varname (@{$globals}) { 245 next if $exemptions{$varname}; 246 next if $varname !~ m/ $carat_re /xms; 247 print {$test_file} "$varname= ();\n"; 248 } 249 250 print {$test_file} <<"END_CODE"; 251 252=== 253--- dscr: Named magic variables, fail = (non-local) = 254--- failures: $numvars 255--- params: 256--- input 257END_CODE 258 259 for my $varname (@{$globals}) { 260 next if $exemptions{$varname}; 261 print {$test_file} "\@foo = ($varname) = ();\n"; 262 } 263 264 print {$test_file} <<"END_CODE"; 265 266=== 267--- dscr: Named magic variables, fail (non-local) 268--- failures: $numvars 269--- params: 270--- input 271END_CODE 272 273 for my $varname (@{$globals}) { 274 next if $exemptions{$varname}; 275 print {$test_file} "($varname) = ();\n"; 276 } 277 278 return; 279} 280 281 282sub print_fail_non_local_deref { 283 my ($test_file, $globals) = @_; 284 285 my %subscript = ( 286 '%' => '{foo}', 287 '@' => '[0]', 288 ); 289 290 my @derefs = grep { $subscript{substr $_, 0, 1} && !$exemptions{$_} } 291 @{ $globals }; 292 my $numvars = scalar @derefs; 293 294 print {$test_file} <<"END_CODE"; 295 296=== 297--- dscr: Named magic variables, fail non-local dereferenced 298--- failures: $numvars 299--- params: 300--- input 301END_CODE 302 303 foreach my $varname ( @derefs ) { 304 my ($sigil, $barename) = $varname =~ m/ (.)(.*) /smx; 305 print {$test_file} '$', $barename, 306 $subscript{$sigil}, " = 'bar';\n"; 307 } 308 309} 310 311 312sub print_footer { 313 my ($test_file) = @_; 314 315 print {$test_file} <<'END_CODE'; 316 317=== 318--- dscr: Allowing a variable with a particular sigil doesn't allow other variables with the same name but different sigils 319--- failures: 1 320--- params: {require_localized_punctuation_vars => {allow => '$ARGV'}} 321--- input 322@ARGV = (1, 2, 3); 323 324=== 325--- dscr: Allow "my" as well, RT #33937 326--- failures: 0 327--- params: 328--- input 329for my $entry ( 330 sort { 331 my @a = split m{,}xms, $a; 332 my @b = split m{,}xms, $b; 333 $a[0] cmp $b[0] || $a[1] <=> $b[1] 334 } qw( b,6 c,3 ) 335 ) 336{ 337 print; 338} 339 340END_CODE 341 342 return; 343} 344 345