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