use strict;
use warnings;
use Perl::Lint::Policy::ValuesAndExpressions::RequireConstantVersion;
use t::Policy::Util qw/fetch_violations/;
use Test::Base::Less;

my $class_name = 'ValuesAndExpressions::RequireConstantVersion';

filters {
    params => [qw/eval/],
};

for my $block (blocks) {
    my $violations = fetch_violations($class_name, $block->input, $block->params);
    is scalar @$violations, $block->failures, $block->dscr;
}

done_testing;

__DATA__

===
--- dscr: basic passes
--- failures: 0
--- params:
--- input
our $VERSION = 2.718;
our $VERSION = $VERSION = 2.718;
$VERSION = '3.14159';
$VERSION = "3.14159";
$VERSION = "foo\$bar";
our $VERSION = q{1.618};
our $VERSION = qq{1.618};
use version; $VERSION = qv('1.2.3');
use version; $VERSION = qv("1.2.3");
# The following from ExtUtils::MakeMaker
(our $Revision = $VERSION) =~ s{_}{};

===
--- dscr: basic failures
--- failures: 7
--- params:
--- input
our $VERSION = "$foo";
our $VERSION = eval $VERSION;
our $VERSION = qq{foo\\$bar};
our ( $VERSION ) = q$REVISION: 42$ =~ m/(\d+)/;
( $VERSION = '$REVISION: 42$' ) =~ s/.*\s+(\d+).*/$1/;
use Foo; $VERSION = $Foo::VERSION;
use version; $VERSION = qv("1.$foo.3");

===
--- dscr: require 'use version' before qv()
--- failures: 1
--- params:
--- input
$VERSION = qv('1.2.3');

===
--- dscr: require 'use version' before version->new()
--- failures: 1
--- params:
--- input
$VERSION = version->new('1.2.3');

===
--- dscr: passes involving other assignment operators
--- failures: 0
--- params:
--- input
our $VERSION ||= 1.23;
our $VERSION ||= '1.23';
our $VERSION ||= "1.23";
use version; our $VERSION = version->new('1.2.3');

===
--- dscr: failures involving other assignment operators
--- failures: 4
--- params:
--- input
our $VERSION ||= qw{$Revision 42 $}[1];
our $VERSION ||= $Foo::VERSION;
our $VERSION ||= "$Foo::VERSION";
our $VERSION ||= version->new('1.2.3');

===
--- dscr: passes from the ProhibitMagicNumbers.run treasury
--- failures: 0
--- params:
--- input
our $VERSION : unique = "1.23";
our $VERSION : unique = '1.23';
our $VERSION = "1.2.3";
our $VERSION = "1.2.3.0";
our $VERSION = "1.2.3.blah";
our $VERSION = "1.23 2005-05-20";
our $VERSION = "1.23";
our $VERSION = "1.23, 2004-12-07";
our $VERSION = "1.23_blah";
our $VERSION = "1.23blah";
our $VERSION = "1.2_3";
our $VERSION = "123";
our $VERSION = "INSERT";
our $VERSION = '$Revision$';
our $VERSION = '-123 blah';
our $VERSION = '1.2.3';
our $VERSION = '1.2.3.0';
our $VERSION = '1.2.3blah';
our $VERSION = '1.23';
our $VERSION = '1.23_blah';
our $VERSION = '1.23blah';
our $VERSION = '1.2_3';
our $VERSION = '123';
our $VERSION = 1.23;
our $VERSION = 1.2_3;
our $VERSION = 123;
our $VERSION = q$0.04$;
our $VERSION = q$Revision$;
our $VERSION = q(0.14);
# Should the following be allowed? I am not sure I really know what qv() means
# without the 'use version;'.
# our $VERSION = qv('1.2.3');
# Hmmm - this is not technically a violation
our $VERSION = qw(1.2.3);
# Should the following be allowed? I am not sure I really know what
# version->new() means without the 'use version;'.
# our $VERSION = version->new('1.2.3');
# our $VERSION = version->new(qw$Revision$);
our ($VERSION) = "1.23";
our ($VERSION) = '1.23';
our ($VERSION) = 1.23;
use version; our $VERSION = 1.23;
use version; our $VERSION = qv("1.2.3");
use version; our $VERSION = qv('1.2.3');
use version; our $VERSION = qv('1.23');
use version; our $VERSION = version->new('1.23');
# V-strings are deprecated, but ...
our $VERSION = 1.2.3;
our $VERSION = v1.2.3.0;
our $VERSION = v1.2.3;
our $VERSION = v1.23;

===
--- dscr: failures from the ProhibitMagicNumbers.run treasury
--- failures: 108
--- params:
--- input
(our $VERSION = q$Revision$) =~ s/Revision //;
(our $VERSION) = '$Revision$' =~ /([\d.]+)/;
(our $VERSION) = sprintf "%d", q$Revision$ =~ /Revision:\s+(\S+)/;
our $VERSION = "$local_variable v1.23";
our $VERSION = "1." . sprintf "%d", q$Revision$ =~ /: (\d+)/;
our $VERSION = "1.23 (liblgrp version $local_variable)";
our $VERSION = $SomeOtherModule::VERSION;
# Technically the following is a constant, but it is also one of the things
# the policy is designed to prevent.
our $VERSION = $VERSION = (qw($Revision$))[1];
our $VERSION = $local_variable;
our $VERSION = '$Date$'; $VERSION =~ s|^\$Date:\s*([0-9]{4})/([0-9]{2})/([0-9]{2})\s.*|\1.\2.\3| ;
our $VERSION = '$Revision$' =~ /\$Revision:\s+([^\s]+)/;
# our $VERSION = '1.' . qw $Revision$[1]; # TODO Possibly Compiler::Lexers' misrecognizing
our $VERSION = '1.' . sprintf "%d", (qw($Revision$))[1];
our $VERSION = '1.' . sprintf("%d", (qw($Revision$))[1]);
# In practice the following is a constant, but if someone goes this far out of
# their way to obfuscate a constant, I for one am not going to dissapoint
# them.
our $VERSION = '1.23' || do { q $Revision$ =~ /(\d+)/; sprintf "%4.2f", $1 / 100 };
our $VERSION = ('$Revision$' =~ /(\d+.\d+)/)[ 0];
our $VERSION = ('$Revision$' =~ /(\d+\.\d+)/);
our $VERSION = ('$Revision$' =~ m/(\d+)/)[0];
our $VERSION = ((require SomeOtherModule), $SomeOtherModule::VERSION)[1];
our $VERSION = (q$Revision$ =~ /([\d\.]+)/);
our $VERSION = (q$Revision$ =~ /(\d+)/g)[0];
our $VERSION = (qq$Revision$ =~ /(\d+)/)[0];
our $VERSION = (qw$Revision$)[-1];
our $VERSION = (qw$Revision$)[1];
our $VERSION = (qw($Revision$))[1];
our $VERSION = (split(/ /, '$Revision$'))[1];
our $VERSION = (split(/ /, '$Revision$'))[2];
our $VERSION = SomeOtherModule::RCSVersion('$Revision$');
our $VERSION = SomeOtherModule::VERSION;
our $VERSION = [ qw{ $Revision$ } ]->[1];
our $VERSION = do { (my $v = q%version: 1.23 %) =~ s/.*://; sprintf("%d.%d", split(/\./, $v), 0) };
our $VERSION = do { (my $v = q%version: 123 %) =~ s/.*://; sprintf("%d.%d", split(/\./, $v), 0) };
our $VERSION = do { q $Revision$ =~ /(\d+)/; sprintf "%4.2f", $1 / 100 };
our $VERSION = do { q$Revision$ =~ /Revision: (\d+)/; sprintf "1.%d", $1; };
our $VERSION = do { require mod_perl2; $mod_perl2::VERSION };
our $VERSION = do {(q$URL$=~ m$.*/(?:tags|branches)/([^/ \t]+)$)[0] || "0.0"};
our $VERSION = eval { require version; version::qv((qw$Revision$)[1] / 1000) };
# Should the following be allowed? I really don't know what 'qv' means without
# the leading 'use version;'.
our $VERSION = qv('1.2.3');
our $VERSION = sprintf "%.02f", $local_variable/100 + 0.3;
our $VERSION = sprintf "%.3f", 123 + substr(q$Revision$, 4)/1000;
our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)\.(\d+)/;
our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)/g;
our $VERSION = sprintf "%d.%d", '$Revision$' =~ /(\d+)\.(\d+)/;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ /: (\d+)\.(\d+)/;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)/g;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/g;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ /: (\d+)\.(\d+)/;
our $VERSION = sprintf "%d.%d", q$Revision$ =~ m/ (\d+) \. (\d+) /xg;
our $VERSION = sprintf "%d.%d", q$Revision$ ~~ m:P5:g/(\d+)/;
our $VERSION = sprintf "%d.%d%d", (split /\D+/, '$Name: beta0_1_1 $')[1..3];
our $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;
our $VERSION = sprintf "1.%d", '$Revision$' =~ /(\d+)/;
our $VERSION = sprintf "1.%d", q$Revision$ =~ /(\d+)/g;
our $VERSION = sprintf '%d.%d', (q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf '%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/;
our $VERSION = sprintf '%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/;
our $VERSION = sprintf '%s', 'q$Revision$' =~ /\S+\s+(\S+)\s+/ ;
our $VERSION = sprintf '%s', 'q$Revision$' =~ /\S+\s+(\S+)\s+/ ;
our $VERSION = sprintf '%s', q$Revision$ =~ /Revision:\s+(\S+)\s+/ ;
our $VERSION = sprintf '%s', q{$Revision$} =~ /\S+\s+(\S+)/ ;
our $VERSION = sprintf '1.%d', (q$Revision$ =~ /\D(\d+)\s*$/)[0] + 15;
our $VERSION = sprintf("%d", q$Id: SomeModule.pm,v 1.23 2006/04/10 22:39:38 matthew Exp $ =~ /\s(\d+)\s/);
our $VERSION = sprintf("%d", q$Id: SomeModule.pm,v 1.23 2006/04/10 22:39:39 matthew Exp $ =~ /\s(\d+)\s/);
our $VERSION = sprintf("%d.%d", "Revision: 2006.0626" =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d", '$Name: v0_018-2006-06-15b $' =~ /(\d+)_(\d+)/, 0, 0);
our $VERSION = sprintf("%d.%d", 0, q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d", q$Name: REL-0-13 $ =~ /(\d+)-(\d+)/, 999, 99);
our $VERSION = sprintf("%d.%d", q$Name: ical-parser-html-1-6 $ =~ /(\d+)-(\d+)/);
our $VERSION = sprintf("%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d", q$Revision$ =~ /(\d+)\.(\d+)/o);
our $VERSION = sprintf("%d.%d", q$Revision$ =~ m/(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d", q$Revision$=~/(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d", q'$Revision$' =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf("%d.%d.%d", 0, q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf("1.%d", q$Revision$ =~ / (\d+) /);
our $VERSION = sprintf("1.%d", q$Revision$ =~ /(\d+)/);
our $VERSION = sprintf("1.2%d%d", q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf('%d.%d', '$Revision$' =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf('%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = sprintf('%d.%d', q$Revision$ =~ /(\d+)\.(\d+)/);
our $VERSION = substr q$Revision$, 10;
our $VERSION = substr(q$Revision$, 10);
# Initially at least this is a violation simply because of the hoops that need
# to be jumped through to make it work.
our ($PACKAGE, $VERSION) = ('') x 2;
# Should the following be allowed? I am not sure I really know what
# version->new() means without the leading 'use version;'.
our $VERSION = version->new('1.2.3');
our $VERSION = version->new(qw$Revision$);
our ($VERSION) = $SomeOtherModule::VERSION;
our ($VERSION) = '$Revision$' =~ /\$Revision:\s+([^\s]+)/;
our ($VERSION) = '$Revision$' =~ /\$Revision:\s+([^\s]+)/;
our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }x;
our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }xm;
our ($VERSION) = '$Revision$'=~/(\d+(\.\d+))/;
our ($VERSION) = '$Revision$' =~ m{ \$Revision: \s+ (\S+) }x;
# Another case of a constant so obfuscated as to perhaps not be worth the
# analysis to straighten it out.
our ($VERSION) = '1.23' =~ /([.,\d]+)/;
our ($VERSION) = ($local_variable =~ /(\d+\.\d+)/);
our ($VERSION) = ('$Revision$' =~ /(\d+\.\d+)/) ;
our ($VERSION) = ('$Revision$' =~ /(\d+\.\d+)/);
our ($VERSION) = ('$Revision$' =~ m/([\.\d]+)/) ;
our ($VERSION) = (q$Revision$ =~ /([\d\.]+)/);
our ($VERSION) = (qq$Revision$ =~ /(\d+)/)[0];
our ($VERSION) = q$Revision$ =~ /Revision:\s+(\S+)/ or $VERSION = "1.23";
our ($VERSION) = q$Revision$ =~ /Revision:\s+(\S+)/ or $VERSION = '1.23';
our ($VERSION) = q$Revision$ =~ /[\d.]+/g;
our ($VERSION) = q$Revision$ =~ /^Revision:\s+(\S+)/ or $VERSION = "1.23";
require SomeOtherModule; our $VERSION = $SomeOtherModule::VERSION;
use SomeOtherModule; our $VERSION = $SomeOtherModule::VERSION;
use SomeOtherModule; our $VERSION = SomeOtherModule::VERSION;
use base 'SomeOtherModule'; our $VERSION = $SomeOtherModule::VERSION;
use version; our $VERSION = qv((qw$Revision$)[1] / 1000);

===
--- dscr: version-like things are OK without 'use version;' if explicitly allowed
--- failures: 0
--- params: {require_constant_version => {allow_version_without_use_on_same_line => '1'}}
--- input
our $VERSION = qv('1.2.3');
our $VERSION = version->new('1.2.3');
our $VERSION = version->new(qw$Revision$);

===
--- dscr: RT #55600 ( $bar = sprintf '%s', $VERSION ) =~ s/0// false positive
--- failures: 0
--- params:
--- input
# This is cut-and-paste directly from the RT ticket. I did not make it up.
(my $BAR = sprintf q{%s/%s}, __PACKAGE__, $VERSION) =~ s{o\z}{}xms;

# The following were not issues raised in the ticket, but ought to pass as a
# result of the work done for the ticket.

( my $BAR = ___PACKAGE__ . '/' . $VERSION ) =~ s{ o \z }{}xms;
( my $BAR = join '/', __PACKAGE__, $VERSION ) =~ s{ o \z }{}xms;

# In fact, the following should pass also, though I can't imagine why anyone
# would do it.

sprintf( q{%s/%s}, __PACKAGE__, $VERSION ) =~ s{ o \z }{}xms;

===
--- dscr: no lint
--- failures: 3
--- params:
--- input
our $VERSION = "$foo";
our $VERSION = eval $VERSION;
our $VERSION = qq{foo\\$bar}; ## no lint
our ( $VERSION ) = q$REVISION: 42$ =~ m/(\d+)/;

