1use strict; 2use warnings; 3use Perl::Lint::Policy::ValuesAndExpressions::RequireConstantVersion; 4use t::Policy::Util qw/fetch_violations/; 5use Test::Base::Less; 6 7my $class_name = 'ValuesAndExpressions::RequireConstantVersion'; 8 9filters { 10 params => [qw/eval/], 11}; 12 13for my $block (blocks) { 14 my $violations = fetch_violations($class_name, $block->input, $block->params); 15 is scalar @$violations, $block->failures, $block->dscr; 16} 17 18done_testing; 19 20__DATA__ 21 22=== 23--- dscr: basic passes 24--- failures: 0 25--- params: 26--- input 27our $VERSION = 2.718; 28our $VERSION = $VERSION = 2.718; 29$VERSION = '3.14159'; 30$VERSION = "3.14159"; 31$VERSION = "foo\$bar"; 32our $VERSION = q{1.618}; 33our $VERSION = qq{1.618}; 34use version; $VERSION = qv('1.2.3'); 35use version; $VERSION = qv("1.2.3"); 36# The following from ExtUtils::MakeMaker 37(our $Revision = $VERSION) =~ s{_}{}; 38 39=== 40--- dscr: basic failures 41--- failures: 7 42--- params: 43--- input 44our $VERSION = "$foo"; 45our $VERSION = eval $VERSION; 46our $VERSION = qq{foo\\$bar}; 47our ( $VERSION ) = q$REVISION: 42$ =~ m/(\d+)/; 48( $VERSION = '$REVISION: 42$' ) =~ s/.*\s+(\d+).*/$1/; 49use Foo; $VERSION = $Foo::VERSION; 50use version; $VERSION = qv("1.$foo.3"); 51 52=== 53--- dscr: require 'use version' before qv() 54--- failures: 1 55--- params: 56--- input 57$VERSION = qv('1.2.3'); 58 59=== 60--- dscr: require 'use version' before version->new() 61--- failures: 1 62--- params: 63--- input 64$VERSION = version->new('1.2.3'); 65 66=== 67--- dscr: passes involving other assignment operators 68--- failures: 0 69--- params: 70--- input 71our $VERSION ||= 1.23; 72our $VERSION ||= '1.23'; 73our $VERSION ||= "1.23"; 74use version; our $VERSION = version->new('1.2.3'); 75 76=== 77--- dscr: failures involving other assignment operators 78--- failures: 4 79--- params: 80--- input 81our $VERSION ||= qw{$Revision 42 $}[1]; 82our $VERSION ||= $Foo::VERSION; 83our $VERSION ||= "$Foo::VERSION"; 84our $VERSION ||= version->new('1.2.3'); 85 86=== 87--- dscr: passes from the ProhibitMagicNumbers.run treasury 88--- failures: 0 89--- params: 90--- input 91our $VERSION : unique = "1.23"; 92our $VERSION : unique = '1.23'; 93our $VERSION = "1.2.3"; 94our $VERSION = "1.2.3.0"; 95our $VERSION = "1.2.3.blah"; 96our $VERSION = "1.23 2005-05-20"; 97our $VERSION = "1.23"; 98our $VERSION = "1.23, 2004-12-07"; 99our $VERSION = "1.23_blah"; 100our $VERSION = "1.23blah"; 101our $VERSION = "1.2_3"; 102our $VERSION = "123"; 103our $VERSION = "INSERT"; 104our $VERSION = '$Revision$'; 105our $VERSION = '-123 blah'; 106our $VERSION = '1.2.3'; 107our $VERSION = '1.2.3.0'; 108our $VERSION = '1.2.3blah'; 109our $VERSION = '1.23'; 110our $VERSION = '1.23_blah'; 111our $VERSION = '1.23blah'; 112our $VERSION = '1.2_3'; 113our $VERSION = '123'; 114our $VERSION = 1.23; 115our $VERSION = 1.2_3; 116our $VERSION = 123; 117our $VERSION = q$0.04$; 118our $VERSION = q$Revision$; 119our $VERSION = q(0.14); 120# Should the following be allowed? I am not sure I really know what qv() means 121# without the 'use version;'. 122# our $VERSION = qv('1.2.3'); 123# Hmmm - this is not technically a violation 124our $VERSION = qw(1.2.3); 125# Should the following be allowed? I am not sure I really know what 126# version->new() means without the 'use version;'. 127# our $VERSION = version->new('1.2.3'); 128# our $VERSION = version->new(qw$Revision$); 129our ($VERSION) = "1.23"; 130our ($VERSION) = '1.23'; 131our ($VERSION) = 1.23; 132use version; our $VERSION = 1.23; 133use version; our $VERSION = qv("1.2.3"); 134use version; our $VERSION = qv('1.2.3'); 135use version; our $VERSION = qv('1.23'); 136use version; our $VERSION = version->new('1.23'); 137# V-strings are deprecated, but ... 138our $VERSION = 1.2.3; 139our $VERSION = v1.2.3.0; 140our $VERSION = v1.2.3; 141our $VERSION = v1.23; 142 143=== 144--- dscr: failures from the ProhibitMagicNumbers.run treasury 145--- failures: 108 146--- params: 147--- input 148(our $VERSION = q$Revision$) =~ s/Revision //; 149(our $VERSION) = '$Revision$' =~ /([\d.]+)/; 150(our $VERSION) = sprintf "%d", q$Revision$ =~ /Revision:\s+(\S+)/; 151our $VERSION = "$local_variable v1.23"; 152our $VERSION = "1." . sprintf "%d", q$Revision$ =~ /: (\d+)/; 153our $VERSION = "1.23 (liblgrp version $local_variable)"; 154our $VERSION = $SomeOtherModule::VERSION; 155# Technically the following is a constant, but it is also one of the things 156# the policy is designed to prevent. 157our $VERSION = $VERSION = (qw($Revision$))[1]; 158our $VERSION = $local_variable; 159our $VERSION = '$Date$'; $VERSION =~ s|^\$Date:\s*([0-9]{4})/([0-9]{2})/([0-9]{2})\s.*|\1.\2.\3| ; 160our $VERSION = '$Revision$' =~ /\$Revision:\s+([^\s]+)/; 161# our $VERSION = '1.' . qw $Revision$[1]; # TODO Possibly Compiler::Lexers' misrecognizing 162our $VERSION = '1.' . sprintf "%d", (qw($Revision$))[1]; 163our $VERSION = '1.' . sprintf("%d", (qw($Revision$))[1]); 164# In practice the following is a constant, but if someone goes this far out of 165# their way to obfuscate a constant, I for one am not going to dissapoint 166# them. 167our $VERSION = '1.23' || do { q $Revision$ =~ /(\d+)/; sprintf "%4.2f", $1 / 100 }; 168our $VERSION = ('$Revision$' =~ /(\d+.\d+)/)[ 0]; 169our $VERSION = ('$Revision$' =~ /(\d+\.\d+)/); 170our $VERSION = ('$Revision$' =~ m/(\d+)/)[0]; 171our $VERSION = ((require SomeOtherModule), $SomeOtherModule::VERSION)[1]; 172our $VERSION = (q$Revision$ =~ /([\d\.]+)/); 173our $VERSION = (q$Revision$ =~ /(\d+)/g)[0]; 174our $VERSION = (qq$Revision$ =~ /(\d+)/)[0]; 175our $VERSION = (qw$Revision$)[-1]; 176our $VERSION = (qw$Revision$)[1]; 177our $VERSION = (qw($Revision$))[1]; 178our $VERSION = (split(/ /, '$Revision$'))[1]; 179our $VERSION = (split(/ /, '$Revision$'))[2]; 180our $VERSION = SomeOtherModule::RCSVersion('$Revision$'); 181our $VERSION = SomeOtherModule::VERSION; 182our $VERSION = [ qw{ $Revision$ } ]->[1]; 183our $VERSION = do { (my $v = q%version: 1.23 %) =~ s/.*://; sprintf("%d.%d", split(/\./, $v), 0) }; 184our $VERSION = do { (my $v = q%version: 123 %) =~ s/.*://; sprintf("%d.%d", split(/\./, $v), 0) }; 185our $VERSION = do { q $Revision$ =~ /(\d+)/; sprintf "%4.2f", $1 / 100 }; 186our $VERSION = do { q$Revision$ =~ /Revision: (\d+)/; sprintf "1.%d", $1; }; 187our $VERSION = do { require mod_perl2; $mod_perl2::VERSION }; 188our $VERSION = do {(q$URL$=~ m$.*/(?:tags|branches)/([^/ \t]+)$)[0] || "0.0"}; 189our $VERSION = eval { require version; version::qv((qw$Revision$)[1] / 1000) }; 190# Should the following be allowed? I really don't know what 'qv' means without 191# the leading 'use version;'. 192our $VERSION = qv('1.2.3'); 193our $VERSION = sprintf "%.02f", $local_variable/100 + 0.3; 194our $VERSION = sprintf "%.3f", 123 + substr(q$Revision$, 4)/1000; 195our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)\.(\d+)/; 196our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)/g; 197our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)\.(\d+)/; 198our $VERSION = sprintf "%d.%d", q$Revision$ =~ /: (\d+)\.(\d+)/; 199our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)/g; 200our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/; 201our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/g; 202our $VERSION = sprintf "%d.%d", q$Revision$ =~ /: (\d+)\.(\d+)/; 203our $VERSION = sprintf "%d.%d", q$Revision$ =~ m/ (\d+) \. (\d+) /xg; 204our $VERSION = sprintf "%d.%d", q$Revision$ ~~ m:P5:g/(\d+)/; 205our $VERSION = sprintf "%d.%d%d", (split /\D+/, '$Name: beta0_1_1 $')[1..3]; 206our $VERSION = sprintf "%s.%s%s", q$Name: Rel-0_90 $ =~ /^Name: Rel-(\d+)_(\d+)(_\d+|)\s*$/, 999, "00", join "", (gmtime)[5] +1900, map {sprintf "%d", $_} (gmtime)[4]+1; 207our $VERSION = sprintf "1.%d", '$Revision$' =~ /(\d+)/; 208our $VERSION = sprintf "1.%d", q$Revision$ =~ /(\d+)/g; 209our $VERSION = sprintf '%d.%d', (q$Revision$ =~ /(\d+)\.(\d+)/); 210our $VERSION = sprintf '%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/; 211our $VERSION = sprintf '%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/; 212our $VERSION = sprintf '%s', 'q$Revision$' =~ /\S+\s+(\S+)\s+/ ; 213our $VERSION = sprintf '%s', 'q$Revision$' =~ /\S+\s+(\S+)\s+/ ; 214our $VERSION = sprintf '%s', q$Revision$ =~ /Revision:\s+(\S+)\s+/ ; 215our $VERSION = sprintf '%s', q{$Revision$} =~ /\S+\s+(\S+)/ ; 216our $VERSION = sprintf '1.%d', (q$Revision$ =~ /\D(\d+)\s*$/)[0] + 15; 217our $VERSION = sprintf("%d", q$Id: SomeModule.pm,v 1.23 2006/04/10 22:39:38 matthew Exp $ =~ /\s(\d+)\s/); 218our $VERSION = sprintf("%d", q$Id: SomeModule.pm,v 1.23 2006/04/10 22:39:39 matthew Exp $ =~ /\s(\d+)\s/); 219our $VERSION = sprintf("%d.%d", "Revision: 2006.0626" =~ /(\d+)\.(\d+)/); 220our $VERSION = sprintf("%d.%d", '$Name: v0_018-2006-06-15b $' =~ /(\d+)_(\d+)/, 0, 0); 221our $VERSION = sprintf("%d.%d", 0, q$Revision$ =~ /(\d+)\.(\d+)/); 222our $VERSION = sprintf("%d.%d", q$Name: REL-0-13 $ =~ /(\d+)-(\d+)/, 999, 99); 223our $VERSION = sprintf("%d.%d", q$Name: ical-parser-html-1-6 $ =~ /(\d+)-(\d+)/); 224our $VERSION = sprintf("%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/); 225our $VERSION = sprintf("%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/o); 226our $VERSION = sprintf("%d.%d", q$Revision$ =~ m/(\d+)\.(\d+)/); 227our $VERSION = sprintf("%d.%d", q$Revision$=~/(\d+)\.(\d+)/); 228our $VERSION = sprintf("%d.%d", q'$Revision$' =~ /(\d+)\.(\d+)/); 229our $VERSION = sprintf("%d.%d.%d", 0, q$Revision$ =~ /(\d+)\.(\d+)/); 230our $VERSION = sprintf("1.%d", q$Revision$ =~ / (\d+) /); 231our $VERSION = sprintf("1.%d", q$Revision$ =~ /(\d+)/); 232our $VERSION = sprintf("1.2%d%d", q$Revision$ =~ /(\d+)\.(\d+)/); 233our $VERSION = sprintf('%d.%d', '$Revision$' =~ /(\d+)\.(\d+)/); 234our $VERSION = sprintf('%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/); 235our $VERSION = sprintf('%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/); 236our $VERSION = substr q$Revision$, 10; 237our $VERSION = substr(q$Revision$, 10); 238# Initially at least this is a violation simply because of the hoops that need 239# to be jumped through to make it work. 240our ($PACKAGE, $VERSION) = ('') x 2; 241# Should the following be allowed? I am not sure I really know what 242# version->new() means without the leading 'use version;'. 243our $VERSION = version->new('1.2.3'); 244our $VERSION = version->new(qw$Revision$); 245our ($VERSION) = $SomeOtherModule::VERSION; 246our ($VERSION) = '$Revision$' =~ /\$Revision:\s+([^\s]+)/; 247our ($VERSION) = '$Revision$' =~ /\$Revision:\s+([^\s]+)/; 248our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }x; 249our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }xm; 250our ($VERSION) = '$Revision$'=~/(\d+(\.\d+))/; 251our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }x; 252# Another case of a constant so obfuscated as to perhaps not be worth the 253# analysis to straighten it out. 254our ($VERSION) = '1.23' =~ /([.,\d]+)/; 255our ($VERSION) = ($local_variable =~ /(\d+\.\d+)/); 256our ($VERSION) = ('$Revision$' =~ /(\d+\.\d+)/) ; 257our ($VERSION) = ('$Revision$' =~ /(\d+\.\d+)/); 258our ($VERSION) = ('$Revision$' =~ m/([\.\d]+)/) ; 259our ($VERSION) = (q$Revision$ =~ /([\d\.]+)/); 260our ($VERSION) = (qq$Revision$ =~ /(\d+)/)[0]; 261our ($VERSION) = q$Revision$ =~ /Revision:\s+(\S+)/ or $VERSION = "1.23"; 262our ($VERSION) = q$Revision$ =~ /Revision:\s+(\S+)/ or $VERSION = '1.23'; 263our ($VERSION) = q$Revision$ =~ /[\d.]+/g; 264our ($VERSION) = q$Revision$ =~ /^Revision:\s+(\S+)/ or $VERSION = "1.23"; 265require SomeOtherModule; our $VERSION = $SomeOtherModule::VERSION; 266use SomeOtherModule; our $VERSION = $SomeOtherModule::VERSION; 267use SomeOtherModule; our $VERSION = SomeOtherModule::VERSION; 268use base 'SomeOtherModule'; our $VERSION = $SomeOtherModule::VERSION; 269use version; our $VERSION = qv((qw$Revision$)[1] / 1000); 270 271=== 272--- dscr: version-like things are OK without 'use version;' if explicitly allowed 273--- failures: 0 274--- params: {require_constant_version => {allow_version_without_use_on_same_line => '1'}} 275--- input 276our $VERSION = qv('1.2.3'); 277our $VERSION = version->new('1.2.3'); 278our $VERSION = version->new(qw$Revision$); 279 280=== 281--- dscr: RT #55600 ( $bar = sprintf '%s', $VERSION ) =~ s/0// false positive 282--- failures: 0 283--- params: 284--- input 285# This is cut-and-paste directly from the RT ticket. I did not make it up. 286(my $BAR = sprintf q{%s/%s}, __PACKAGE__, $VERSION) =~ s{o\z}{}xms; 287 288# The following were not issues raised in the ticket, but ought to pass as a 289# result of the work done for the ticket. 290 291( my $BAR = ___PACKAGE__ . '/' . $VERSION ) =~ s{ o \z }{}xms; 292( my $BAR = join '/', __PACKAGE__, $VERSION ) =~ s{ o \z }{}xms; 293 294# In fact, the following should pass also, though I can't imagine why anyone 295# would do it. 296 297sprintf( q{%s/%s}, __PACKAGE__, $VERSION ) =~ s{ o \z }{}xms; 298 299=== 300--- dscr: no lint 301--- failures: 3 302--- params: 303--- input 304our $VERSION = "$foo"; 305our $VERSION = eval $VERSION; 306our $VERSION = qq{foo\\$bar}; ## no lint 307our ( $VERSION ) = q$REVISION: 42$ =~ m/(\d+)/; 308 309