mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Add rule namespaces: style, lint, layout (#63)
This commit is contained in:
parent
d9f04af057
commit
4cb5328513
71 changed files with 128 additions and 128 deletions
113
spec/ameba/rule/lint/comparison_to_boolean_spec.cr
Normal file
113
spec/ameba/rule/lint/comparison_to_boolean_spec.cr
Normal file
|
@ -0,0 +1,113 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = ComparisonToBoolean.new
|
||||
|
||||
describe ComparisonToBoolean do
|
||||
it "passes if there is no comparison to boolean" do
|
||||
source = Source.new %(
|
||||
a = true
|
||||
|
||||
if a
|
||||
:ok
|
||||
end
|
||||
|
||||
if true
|
||||
:ok
|
||||
end
|
||||
|
||||
unless s.empty?
|
||||
:ok
|
||||
end
|
||||
|
||||
:ok if a
|
||||
|
||||
:ok if a != 1
|
||||
|
||||
:ok if a == "true"
|
||||
|
||||
case a
|
||||
when true
|
||||
:ok
|
||||
when false
|
||||
:not_ok
|
||||
end
|
||||
)
|
||||
subject.catch(source).should be_valid
|
||||
end
|
||||
|
||||
context "boolean on the right" do
|
||||
it "fails if there is == comparison to boolean" do
|
||||
source = Source.new %(
|
||||
if s.empty? == true
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is != comparison to boolean" do
|
||||
source = Source.new %(
|
||||
if a != false
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is case comparison to boolean" do
|
||||
source = Source.new %(
|
||||
a === true
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
source = Source.new "a != true", "source.cr"
|
||||
subject.catch(source)
|
||||
|
||||
issue = source.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:1"
|
||||
issue.message.should eq "Comparison to a boolean is pointless"
|
||||
end
|
||||
end
|
||||
|
||||
context "boolean on the left" do
|
||||
it "fails if there is == comparison to boolean" do
|
||||
source = Source.new %(
|
||||
if true == s.empty?
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is != comparison to boolean" do
|
||||
source = Source.new %(
|
||||
if false != a
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is case comparison to boolean" do
|
||||
source = Source.new %(
|
||||
true === a
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
source = Source.new "true != a", "source.cr"
|
||||
subject.catch(source).should_not be_valid
|
||||
|
||||
issue = source.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:1"
|
||||
issue.message.should eq "Comparison to a boolean is pointless"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
44
spec/ameba/rule/lint/debugger_statement_spec.cr
Normal file
44
spec/ameba/rule/lint/debugger_statement_spec.cr
Normal file
|
@ -0,0 +1,44 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = DebuggerStatement.new
|
||||
|
||||
describe DebuggerStatement do
|
||||
it "passes if there is no debugger statement" do
|
||||
s = Source.new %(
|
||||
"this is not a debugger statement"
|
||||
s = "debugger"
|
||||
|
||||
def debugger(program)
|
||||
end
|
||||
debugger ""
|
||||
|
||||
class A
|
||||
def debugger
|
||||
end
|
||||
end
|
||||
A.new.debugger
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a debugger statement" do
|
||||
s = Source.new %(
|
||||
a = 2
|
||||
debugger
|
||||
a = a + 1
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
s = Source.new "debugger", "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:1"
|
||||
issue.message.should eq "Possible forgotten debugger statement detected"
|
||||
end
|
||||
end
|
||||
end
|
68
spec/ameba/rule/lint/empty_ensure_spec.cr
Normal file
68
spec/ameba/rule/lint/empty_ensure_spec.cr
Normal file
|
@ -0,0 +1,68 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe EmptyEnsure do
|
||||
subject = EmptyEnsure.new
|
||||
|
||||
it "passes if there is no empty ensure blocks" do
|
||||
s = Source.new %(
|
||||
def some_method
|
||||
do_some_stuff
|
||||
ensure
|
||||
do_something_else
|
||||
end
|
||||
|
||||
begin
|
||||
do_some_stuff
|
||||
ensure
|
||||
do_something_else
|
||||
end
|
||||
|
||||
def method_with_rescue
|
||||
rescue
|
||||
ensure
|
||||
nil
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is an empty ensure in method" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
do_some_stuff
|
||||
ensure
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is an empty ensure in a block" do
|
||||
s = Source.new %(
|
||||
begin
|
||||
do_some_stuff
|
||||
ensure
|
||||
# nothing here
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
s = Source.new %(
|
||||
begin
|
||||
do_some_stuff
|
||||
rescue
|
||||
do_some_other_stuff
|
||||
ensure
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:3:11"
|
||||
issue.message.should eq "Empty `ensure` block detected"
|
||||
end
|
||||
end
|
||||
end
|
110
spec/ameba/rule/lint/empty_expression_spec.cr
Normal file
110
spec/ameba/rule/lint/empty_expression_spec.cr
Normal file
|
@ -0,0 +1,110 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba
|
||||
subject = Rule::Lint::EmptyExpression.new
|
||||
|
||||
def it_detects_empty_expression(code)
|
||||
it "detects empty expression" do
|
||||
s = Source.new code
|
||||
rule = Rule::Lint::EmptyExpression.new
|
||||
rule.catch(s).should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe Rule::Lint::EmptyExpression do
|
||||
it "passes if there is no empty expression" do
|
||||
s = Source.new %(
|
||||
def method()
|
||||
end
|
||||
|
||||
method()
|
||||
method(1, 2, 3)
|
||||
method(nil)
|
||||
|
||||
a = nil
|
||||
a = ""
|
||||
a = 0
|
||||
|
||||
nil
|
||||
:any.nil?
|
||||
|
||||
begin "" end
|
||||
[nil] << nil
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it_detects_empty_expression %(())
|
||||
it_detects_empty_expression %(((())))
|
||||
it_detects_empty_expression %(a = ())
|
||||
it_detects_empty_expression %((();()))
|
||||
it_detects_empty_expression %(if (); end)
|
||||
it_detects_empty_expression %(
|
||||
if foo
|
||||
1
|
||||
elsif ()
|
||||
2
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
case foo
|
||||
when :foo then ()
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
case foo
|
||||
when :foo then 1
|
||||
else
|
||||
()
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
case foo
|
||||
when () then 1
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
def method
|
||||
a = 1
|
||||
()
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
def method
|
||||
rescue
|
||||
()
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
def method
|
||||
begin
|
||||
end
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
begin; end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
begin
|
||||
nil
|
||||
end
|
||||
)
|
||||
it_detects_empty_expression %(
|
||||
begin
|
||||
()
|
||||
end
|
||||
)
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new %(
|
||||
if ()
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:12"
|
||||
issue.message.should eq "Avoid empty expressions"
|
||||
end
|
||||
end
|
||||
end
|
50
spec/ameba/rule/lint/hash_duplicated_key_spec.cr
Normal file
50
spec/ameba/rule/lint/hash_duplicated_key_spec.cr
Normal file
|
@ -0,0 +1,50 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe HashDuplicatedKey do
|
||||
subject = HashDuplicatedKey.new
|
||||
|
||||
it "passes if there is no duplicated keys in a hash literals" do
|
||||
s = Source.new %(
|
||||
h = {"a" => 1, :a => 2, "b" => 3}
|
||||
h = {"a" => 1, "b" => 2, "c" => {"a" => 3, "b" => 4}}
|
||||
h = {} of String => String
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a duplicated key in a hash literal" do
|
||||
s = Source.new %q(
|
||||
h = {"a" => 1, "b" => 2, "a" => 3}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a duplicated key in the inner hash literal" do
|
||||
s = Source.new %q(
|
||||
h = {"a" => 1, "b" => {"a" => 3, "b" => 4, "a" => 5}}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new %q(
|
||||
h = {"a" => 1, "a" => 2}
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:13"
|
||||
issue.message.should eq %(Duplicated keys in hash literal: "a")
|
||||
end
|
||||
|
||||
it "reports multiple duplicated keys" do
|
||||
s = Source.new %q(
|
||||
h = {"key1" => 1, "key1" => 2, "key2" => 3, "key2" => 4}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.message.should eq %(Duplicated keys in hash literal: "key1", "key2")
|
||||
end
|
||||
end
|
||||
end
|
72
spec/ameba/rule/lint/literal_in_condition_spec.cr
Normal file
72
spec/ameba/rule/lint/literal_in_condition_spec.cr
Normal file
|
@ -0,0 +1,72 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = LiteralInCondition.new
|
||||
|
||||
describe LiteralInCondition do
|
||||
it "passes if there is not literals in conditional" do
|
||||
s = Source.new %(
|
||||
if a == 2
|
||||
:ok
|
||||
end
|
||||
|
||||
:ok unless b
|
||||
|
||||
case string
|
||||
when "a"
|
||||
:ok
|
||||
when "b"
|
||||
:ok
|
||||
end
|
||||
|
||||
unless a.nil?
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a predicate in if conditional" do
|
||||
s = Source.new %(
|
||||
if "string"
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a predicate in unless conditional" do
|
||||
s = Source.new %(
|
||||
unless true
|
||||
:ok
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a predicate in case conditional" do
|
||||
s = Source.new %(
|
||||
case [1, 2, 3]
|
||||
when :array
|
||||
:ok
|
||||
when :not_array
|
||||
:also_ok
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
s = Source.new %(
|
||||
puts "hello" if true
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
s.issues.size.should eq 1
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:9"
|
||||
issue.message.should eq "Literal value found in conditional"
|
||||
end
|
||||
end
|
||||
end
|
41
spec/ameba/rule/lint/literal_in_interpolation_spec.cr
Normal file
41
spec/ameba/rule/lint/literal_in_interpolation_spec.cr
Normal file
|
@ -0,0 +1,41 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = LiteralInInterpolation.new
|
||||
|
||||
describe LiteralInInterpolation do
|
||||
it "passes with good interpolation examples" do
|
||||
s = Source.new %q(
|
||||
name = "Ary"
|
||||
"Hello, #{name}"
|
||||
|
||||
"#{name}"
|
||||
|
||||
"Name size: #{name.size}"
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is useless interpolation" do
|
||||
[
|
||||
%q("#{:Ary}"),
|
||||
%q("#{[1, 2, 3]}"),
|
||||
%q("#{true}"),
|
||||
%q("#{false}"),
|
||||
%q("here are #{4} cats"),
|
||||
].each do |str|
|
||||
subject.catch(Source.new str).should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
it "reports rule, pos and message" do
|
||||
s = Source.new %q("#{4}"), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:1"
|
||||
issue.message.should eq "Literal value found in interpolation"
|
||||
end
|
||||
end
|
||||
end
|
85
spec/ameba/rule/lint/percent_arrays_spec.cr
Normal file
85
spec/ameba/rule/lint/percent_arrays_spec.cr
Normal file
|
@ -0,0 +1,85 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe PercentArrays do
|
||||
subject = PercentArrays.new
|
||||
|
||||
it "passes if percent arrays are written correctly" do
|
||||
s = Source.new %q(
|
||||
%i(one two three)
|
||||
%w(one two three)
|
||||
|
||||
%i(1 2 3)
|
||||
%w(1 2 3)
|
||||
|
||||
%i()
|
||||
%w()
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if string percent array has commas" do
|
||||
s = Source.new %( %w(one, two) )
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if string percent array has quotes" do
|
||||
s = Source.new %( %w("one" "two") )
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if symbols percent array has commas" do
|
||||
s = Source.new %( %i(one, two) )
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if symbols percent array has a colon" do
|
||||
s = Source.new %( %i(:one :two) )
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message for %i" do
|
||||
s = Source.new %(
|
||||
%i(:one)
|
||||
), "source.cr"
|
||||
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:9"
|
||||
issue.message.should eq(
|
||||
"Symbols `,:` may be unwanted in %i array literals"
|
||||
)
|
||||
end
|
||||
|
||||
it "reports rule, location and message for %w" do
|
||||
s = Source.new %(
|
||||
%w("one")
|
||||
), "source.cr"
|
||||
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:9"
|
||||
issue.message.should eq(
|
||||
"Symbols `,\"` may be unwanted in %w array literals"
|
||||
)
|
||||
end
|
||||
|
||||
context "properties" do
|
||||
it "allows to configure string_array_unwanted_symbols" do
|
||||
rule = PercentArrays.new
|
||||
rule.string_array_unwanted_symbols = ","
|
||||
s = Source.new %( %w("one") )
|
||||
rule.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "allows to configure symbol_array_unwanted_symbols" do
|
||||
rule = PercentArrays.new
|
||||
rule.symbol_array_unwanted_symbols = ","
|
||||
s = Source.new %( %i(:one) )
|
||||
rule.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
36
spec/ameba/rule/lint/rand_zero_spec.cr
Normal file
36
spec/ameba/rule/lint/rand_zero_spec.cr
Normal file
|
@ -0,0 +1,36 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe RandZero do
|
||||
subject = RandZero.new
|
||||
|
||||
it "passes if it is not rand(1) or rand(0)" do
|
||||
s = Source.new %(
|
||||
rand(1.0)
|
||||
rand(0.11)
|
||||
rand(2)
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if it is rand(0)" do
|
||||
s = Source.new "rand(0)"
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "fails if it is rand(1)" do
|
||||
s = Source.new "rand(1)"
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and a message" do
|
||||
s = Source.new "rand(1)", "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:1"
|
||||
issue.message.should eq "rand(1) always returns 0"
|
||||
end
|
||||
end
|
||||
end
|
165
spec/ameba/rule/lint/shadowed_argument_spec.cr
Normal file
165
spec/ameba/rule/lint/shadowed_argument_spec.cr
Normal file
|
@ -0,0 +1,165 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe ShadowedArgument do
|
||||
subject = ShadowedArgument.new
|
||||
|
||||
it "doesn't report if there is not a shadowed argument" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
baz = 1
|
||||
end
|
||||
|
||||
3.times do |i|
|
||||
a = 1
|
||||
end
|
||||
|
||||
proc = -> (a : Int32) {
|
||||
b = 2
|
||||
}
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowed method argument" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar = 1
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowed block argument" do
|
||||
s = Source.new %(
|
||||
3.times do |i|
|
||||
i = 2
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowed proc argument" do
|
||||
s = Source.new %(
|
||||
->(x : Int32) {
|
||||
x = 20
|
||||
x
|
||||
}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if the argument is referenced before the assignment" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar
|
||||
bar = 1
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if the argument is conditionally reassigned" do
|
||||
s = Source.new %(
|
||||
def foo(bar = nil)
|
||||
bar ||= true
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if the op assign is followed by another assignment" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar ||= 3
|
||||
bar = 43
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if the shadowing assignment is followed by op assign" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar = 42
|
||||
bar ||= 43
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if the argument is unused" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if the argument is shadowed before super" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar = 1
|
||||
super
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
context "branch" do
|
||||
it "doesn't report if the argument is not shadowed in a condition" do
|
||||
s = Source.new %(
|
||||
def foo(bar, baz)
|
||||
bar = 1 if baz
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if the argument is shadowed after the condition" do
|
||||
s = Source.new %(
|
||||
def foo(foo)
|
||||
if something
|
||||
foo = 42
|
||||
end
|
||||
foo = 43
|
||||
foo
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if the argument is conditionally assigned in a branch" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
if something
|
||||
bar ||= 22
|
||||
end
|
||||
bar
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new %(
|
||||
def foo(bar)
|
||||
bar = 22
|
||||
bar
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:3:11"
|
||||
issue.message.should eq "Argument `bar` is assigned before it is used"
|
||||
end
|
||||
end
|
||||
end
|
175
spec/ameba/rule/lint/shadowed_exception_spec.cr
Normal file
175
spec/ameba/rule/lint/shadowed_exception_spec.cr
Normal file
|
@ -0,0 +1,175 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
private def check_shadowed(source, exceptions)
|
||||
s = Ameba::Source.new source
|
||||
Ameba::Rule::Lint::ShadowedException.new.catch(s).should_not be_valid
|
||||
s.issues.first.message.should contain exceptions.join(", ")
|
||||
end
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe ShadowedException do
|
||||
subject = ShadowedException.new
|
||||
|
||||
it "passes if there isn't shadowed exception" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
do_something
|
||||
rescue ArgumentError
|
||||
handle_argument_error_exception
|
||||
rescue Exception
|
||||
handle_exception
|
||||
end
|
||||
|
||||
def method
|
||||
rescue Exception
|
||||
handle_exception
|
||||
end
|
||||
|
||||
def method
|
||||
rescue e : ArgumentError
|
||||
handle_argument_error_exception
|
||||
rescue e : Exception
|
||||
handle_exception
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is a shadowed exception" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
do_something
|
||||
rescue Exception
|
||||
handle_exception
|
||||
rescue ArgumentError
|
||||
handle_argument_error_exception
|
||||
end
|
||||
), %w(ArgumentError)
|
||||
end
|
||||
|
||||
it "fails if there is a custom shadowed exceptions" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
1
|
||||
rescue Exception
|
||||
2
|
||||
rescue MySuperException
|
||||
3
|
||||
end
|
||||
), %w(MySuperException)
|
||||
end
|
||||
|
||||
it "fails if there is a shadowed exception in a type list" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue Exception | IndexError
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there is a first shadowed exception in a type list" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue IndexError | Exception
|
||||
rescue Exception
|
||||
rescue
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there is a shadowed duplicated exception" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue IndexError
|
||||
rescue ArgumentError
|
||||
rescue IndexError
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there is a shadowed duplicated exception in a type list" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue IndexError
|
||||
rescue ArgumentError | IndexError
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there is only shadowed duplicated exceptions" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue IndexError
|
||||
rescue IndexError
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there is only shadowed duplicated exceptions in a type list" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue IndexError | IndexError
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if all rescues are shadowed and there is a catch-all rescue" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue Exception
|
||||
rescue ArgumentError
|
||||
rescue IndexError
|
||||
rescue KeyError | IO::Error
|
||||
rescue
|
||||
end
|
||||
), %w(IndexError KeyError IO::Error)
|
||||
end
|
||||
|
||||
it "fails if there are shadowed exception with args" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue Exception
|
||||
rescue ex : IndexError
|
||||
rescue
|
||||
end
|
||||
), %w(IndexError)
|
||||
end
|
||||
|
||||
it "fails if there are multiple shadowed exceptions" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue Exception
|
||||
rescue ArgumentError
|
||||
rescue IndexError
|
||||
end
|
||||
), %w(ArgumentError IndexError)
|
||||
end
|
||||
|
||||
it "fails if there are multipe shadowed exceptions in a type list" do
|
||||
check_shadowed %(
|
||||
begin
|
||||
rescue Exception
|
||||
rescue ArgumentError | IndexError
|
||||
rescue IO::Error
|
||||
end
|
||||
), %w(ArgumentError IndexError IO::Error)
|
||||
end
|
||||
|
||||
it "reports rule, location and a message" do
|
||||
s = Source.new %q(
|
||||
begin
|
||||
do_something
|
||||
rescue Exception | IndexError
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:3:11"
|
||||
issue.message.should eq(
|
||||
"Exception handler has shadowed exceptions: IndexError"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
140
spec/ameba/rule/lint/shadowing_local_outer_var_spec.cr
Normal file
140
spec/ameba/rule/lint/shadowing_local_outer_var_spec.cr
Normal file
|
@ -0,0 +1,140 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe ShadowingOuterLocalVar do
|
||||
subject = ShadowingOuterLocalVar.new
|
||||
|
||||
it "doesn't report if there is no shadowing" do
|
||||
source = Source.new %(
|
||||
def some_method
|
||||
foo = 1
|
||||
|
||||
3.times do |bar|
|
||||
bar
|
||||
end
|
||||
|
||||
-> (baz : Int32) {}
|
||||
|
||||
-> (bar : String) {}
|
||||
end
|
||||
)
|
||||
|
||||
subject.catch(source).should be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowing in a block" do
|
||||
source = Source.new %(
|
||||
def some_method
|
||||
foo = 1
|
||||
|
||||
3.times do |foo|
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowing in a proc" do
|
||||
source = Source.new %(
|
||||
def some_method
|
||||
foo = 1
|
||||
|
||||
-> (foo : Int32) {}
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a shadowing in an inner scope" do
|
||||
source = Source.new %(
|
||||
def foo
|
||||
foo = 1
|
||||
|
||||
3.times do |i|
|
||||
3.times { |foo| foo }
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if variable is shadowed twice" do
|
||||
source = Source.new %(
|
||||
foo = 1
|
||||
|
||||
3.times do |foo|
|
||||
-> (foo : Int32) { foo + 1 }
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
|
||||
source.issues.size.should eq 2
|
||||
end
|
||||
|
||||
it "reports if a splat block argument shadows local var" do
|
||||
source = Source.new %(
|
||||
foo = 1
|
||||
|
||||
3.times do |*foo|
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if a &block argument is shadowed" do
|
||||
source = Source.new %(
|
||||
def method_with_block(a, &block)
|
||||
3.times do |block|
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
source.issues.first.message.should eq "Shadowing outer local variable `block`"
|
||||
end
|
||||
|
||||
it "reports if there are multiple args and one shadows local var" do
|
||||
source = Source.new %(
|
||||
foo = 1
|
||||
[1, 2, 3].each_with_index do |i, foo|
|
||||
i + foo
|
||||
end
|
||||
)
|
||||
subject.catch(source).should_not be_valid
|
||||
source.issues.first.message.should eq "Shadowing outer local variable `foo`"
|
||||
end
|
||||
|
||||
it "doesn't report if an outer var is reassigned in a block" do
|
||||
source = Source.new %(
|
||||
def foo
|
||||
foo = 1
|
||||
3.times do |i|
|
||||
foo = 2
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(source).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if an argument is a black hole '_'" do
|
||||
source = Source.new %(
|
||||
_ = 1
|
||||
3.times do |_|
|
||||
end
|
||||
)
|
||||
subject.catch(source).should be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
source = Source.new %(
|
||||
foo = 1
|
||||
3.times { |foo| foo + 1 }
|
||||
), "source.cr"
|
||||
subject.catch(source).should_not be_valid
|
||||
|
||||
issue = source.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:3:20"
|
||||
issue.message.should eq "Shadowing outer local variable `foo`"
|
||||
end
|
||||
end
|
||||
end
|
37
spec/ameba/rule/lint/syntax_spec.cr
Normal file
37
spec/ameba/rule/lint/syntax_spec.cr
Normal file
|
@ -0,0 +1,37 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe Syntax do
|
||||
subject = Syntax.new
|
||||
|
||||
it "passes if there is no invalid syntax" do
|
||||
s = Source.new %(
|
||||
def hello
|
||||
puts "totally valid"
|
||||
rescue e: Exception
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is an invalid syntax" do
|
||||
s = Source.new %(
|
||||
def hello
|
||||
puts "invalid"
|
||||
rescue Exception => e
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new "def hello end", "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:1:11"
|
||||
issue.message.should eq "unexpected token: end (expected ';' or newline)"
|
||||
end
|
||||
end
|
||||
end
|
102
spec/ameba/rule/lint/unneded_disable_directive_spec.cr
Normal file
102
spec/ameba/rule/lint/unneded_disable_directive_spec.cr
Normal file
|
@ -0,0 +1,102 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe UnneededDisableDirective do
|
||||
subject = UnneededDisableDirective.new
|
||||
|
||||
it "passes if there are no comments" do
|
||||
s = Source.new %(
|
||||
a = 1
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "passes if there is disable directive" do
|
||||
s = Source.new %(
|
||||
a = 1 # my super var
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if there is disable directive and it is needed" do
|
||||
s = Source.new %Q(
|
||||
# ameba:disable #{NamedRule.name}
|
||||
a = 1
|
||||
)
|
||||
s.add_issue NamedRule.new, location: {3, 9},
|
||||
message: "Useless assignment", status: :disabled
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "passes if there is inline disable directive and it is needed" do
|
||||
s = Source.new %Q(
|
||||
a = 1 # ameba:disable #{NamedRule.name}
|
||||
)
|
||||
s.add_issue NamedRule.new, location: {2, 1},
|
||||
message: "Alarm!", status: :disabled
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "ignores commented out disable directive" do
|
||||
s = Source.new %Q(
|
||||
# # ameba:disable #{NamedRule.name}
|
||||
a = 1
|
||||
)
|
||||
s.add_issue NamedRule.new, location: {3, 1},
|
||||
message: "Alarm!", status: :disabled
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is unneeded directive" do
|
||||
s = Source.new %Q(
|
||||
# ameba:disable #{NamedRule.name}
|
||||
a = 1
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq(
|
||||
"Unnecessary disabling of #{NamedRule.name}"
|
||||
)
|
||||
end
|
||||
|
||||
it "fails if there is inline unneeded directive" do
|
||||
s = Source.new %Q(a = 1 # ameba:disable #{NamedRule.name})
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq(
|
||||
"Unnecessary disabling of #{NamedRule.name}"
|
||||
)
|
||||
end
|
||||
|
||||
it "detects mixed inline directives" do
|
||||
s = Source.new %Q(
|
||||
# ameba:disable Rule1, Rule2
|
||||
a = 1 # ameba:disable Rule3
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 2
|
||||
s.issues.first.message.should contain "Rule1, Rule2"
|
||||
s.issues.last.message.should contain "Rule3"
|
||||
end
|
||||
|
||||
it "fails if there is disabled UnneededDisableDirective" do
|
||||
s = Source.new %Q(
|
||||
# ameba:disable #{UnneededDisableDirective.rule_name}
|
||||
a = 1
|
||||
), "source.cr"
|
||||
s.add_issue UnneededDisableDirective.new, location: {3, 1},
|
||||
message: "Alarm!", status: :disabled
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports issue, location and message" do
|
||||
s = Source.new %Q(
|
||||
# ameba:disable Rule1, Rule2
|
||||
a = 1
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:2:9"
|
||||
issue.message.should eq "Unnecessary disabling of Rule1, Rule2"
|
||||
end
|
||||
end
|
||||
end
|
278
spec/ameba/rule/lint/unused_argument_spec.cr
Normal file
278
spec/ameba/rule/lint/unused_argument_spec.cr
Normal file
|
@ -0,0 +1,278 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = UnusedArgument.new
|
||||
subject.ignore_defs = false
|
||||
|
||||
describe UnusedArgument do
|
||||
it "doesn't report if arguments are used" do
|
||||
s = Source.new %(
|
||||
def method(a, b, c)
|
||||
a + b + c
|
||||
end
|
||||
|
||||
3.times do |i|
|
||||
i + 1
|
||||
end
|
||||
|
||||
->(i : Int32) { i + 1 }
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if method argument is unused" do
|
||||
s = Source.new %(
|
||||
def method(a, b, c)
|
||||
a + b
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
end
|
||||
|
||||
it "reports if block argument is unused" do
|
||||
s = Source.new %(
|
||||
[1,2].each_with_index do |a, i|
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq "Unused argument `i`. If it's necessary, use `_` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
end
|
||||
|
||||
it "reports if proc argument is unused" do
|
||||
s = Source.new %(
|
||||
-> (a : Int32, b : String) do
|
||||
a = a + 1
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
end
|
||||
|
||||
it "reports multiple unused args" do
|
||||
s = Source.new %(
|
||||
def method(a, b, c)
|
||||
nil
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues[0].message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
s.issues[1].message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
s.issues[2].message.should eq "Unused argument `c`. If it's necessary, use `_c` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
end
|
||||
|
||||
it "doesn't report if it is an instance var argument" do
|
||||
s = Source.new %(
|
||||
class A
|
||||
def method(@name)
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if a typed argument is used" do
|
||||
s = Source.new %(
|
||||
def method(x : Int32)
|
||||
3.times do
|
||||
puts x
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if an argument with default value is used" do
|
||||
s = Source.new %(
|
||||
def method(x = 1)
|
||||
puts x
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if argument starts with a _" do
|
||||
s = Source.new %(
|
||||
def method(_x)
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if it is a block and used" do
|
||||
s = Source.new %(
|
||||
def method(&block)
|
||||
block.call
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if block arg is not used" do
|
||||
s = Source.new %(
|
||||
def method(&block)
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if unused and there is yield" do
|
||||
s = Source.new %(
|
||||
def method(&block)
|
||||
yield 1
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if variable is referenced implicitly" do
|
||||
s = Source.new %(
|
||||
class Bar < Foo
|
||||
def method(a, b)
|
||||
super
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if arg if referenced in case" do
|
||||
s = Source.new %(
|
||||
def foo(a)
|
||||
case a
|
||||
when /foo/
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
context "super" do
|
||||
it "reports if variable is not referenced implicitly by super" do
|
||||
s = Source.new %(
|
||||
class Bar < Foo
|
||||
def method(a, b)
|
||||
super a
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.message.should eq "Unused argument `b`. If it's necessary, use `_b` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.message.should eq "Unused argument `a`. If it's necessary, use `_a` " \
|
||||
"as an argument name to indicate that it won't be used."
|
||||
issue.location.to_s.should eq "source.cr:2:22"
|
||||
end
|
||||
end
|
||||
|
||||
context "macro" do
|
||||
it "doesn't report if it is a used macro argument" do
|
||||
s = Source.new %(
|
||||
macro my_macro(arg)
|
||||
{% arg %}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if it is a used macro block argument" do
|
||||
s = Source.new %(
|
||||
macro my_macro(&block)
|
||||
{% block %}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report used macro args with equal names in record" do
|
||||
s = Source.new %(
|
||||
record X do
|
||||
macro foo(a, b)
|
||||
{{a}} + {{b}}
|
||||
end
|
||||
|
||||
macro bar(a, b, c)
|
||||
{{a}} + {{b}} + {{c}}
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "properties" do
|
||||
describe "#ignore_defs" do
|
||||
it "lets the rule to ignore def scopes if true" do
|
||||
subject.ignore_defs = true
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "lets the rule not to ignore def scopes if false" do
|
||||
subject.ignore_defs = false
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "#ignore_blocks" do
|
||||
it "lets the rule to ignore block scopes if true" do
|
||||
subject.ignore_blocks = true
|
||||
s = Source.new %(
|
||||
3.times { |i| puts "yo!" }
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "lets the rule not to ignore block scopes if false" do
|
||||
subject.ignore_blocks = false
|
||||
s = Source.new %(
|
||||
3.times { |i| puts "yo!" }
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "#ignore_procs" do
|
||||
it "lets the rule to ignore proc scopes if true" do
|
||||
subject.ignore_procs = true
|
||||
s = Source.new %(
|
||||
->(a : Int32) {}
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "lets the rule not to ignore proc scopes if false" do
|
||||
subject.ignore_procs = false
|
||||
s = Source.new %(
|
||||
->(a : Int32) {}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
900
spec/ameba/rule/lint/useless_assign_spec.cr
Normal file
900
spec/ameba/rule/lint/useless_assign_spec.cr
Normal file
|
@ -0,0 +1,900 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
describe UselessAssign do
|
||||
subject = UselessAssign.new
|
||||
|
||||
it "does not report used assigments" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports a useless assignment in a method" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports a useless assignment in a proc" do
|
||||
s = Source.new %(
|
||||
->() {
|
||||
a = 2
|
||||
}
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports a useless assignment in a block" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
3.times do
|
||||
a = 1
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports a useless assignment in a proc inside def" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
->() {
|
||||
a = 2
|
||||
}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports a useless assignment in a proc inside a block" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
3.times do
|
||||
->() {
|
||||
a = 2
|
||||
}
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, position and a message" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:3:11"
|
||||
issue.message.should eq "Useless assignment to variable `a`"
|
||||
end
|
||||
|
||||
it "does not report useless assignment of instance var" do
|
||||
s = Source.new %(
|
||||
class Cls
|
||||
def initialize(@name)
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if assignment used in the inner block scope" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
var = true
|
||||
3.times { var = false }
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assigned is not referenced in the inner block scope" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
var = true
|
||||
3.times {}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment in referenced in inner block" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
two = true
|
||||
|
||||
3.times do
|
||||
mutex.synchronize do
|
||||
two = 2
|
||||
end
|
||||
end
|
||||
|
||||
two.should be_true
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if first assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
var = true
|
||||
var = false
|
||||
var
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.first.location.to_s.should eq ":3:11"
|
||||
end
|
||||
|
||||
it "reports if variable reassigned and not used" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
var = true
|
||||
var = false
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable used in a condition" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 1
|
||||
if a
|
||||
nil
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports second assignment as useless" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 1
|
||||
a = a + 1
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable is referenced in other assignment" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
if f = get_something
|
||||
@f = f
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable is referenced in a setter" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
foo = 2
|
||||
table[foo] ||= "bar"
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable is reassigned but not referenced" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
foo = 1
|
||||
puts foo
|
||||
foo = 2
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable is referenced in a call" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
if f = FORMATTER
|
||||
@formatter = f.new
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if a setter is invoked with operator assignment" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
obj = {} of Symbol => Int32
|
||||
obj[:name] = 3
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if global var" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
$? = 3
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if assignment is referenced in a proc" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
called = false
|
||||
->() { called = true }
|
||||
called
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if variable is shadowed in inner scope" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
i = 1
|
||||
3.times do |i|
|
||||
i + 1
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "does not report if parameter is referenced after the branch" do
|
||||
s = Source.new %(
|
||||
def method(param)
|
||||
3.times do
|
||||
param = 3
|
||||
end
|
||||
param
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
context "op assigns" do
|
||||
it "does not report if variable is referenced below the op assign" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 1
|
||||
a += 1
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if variable is referenced in op assign few times" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 1
|
||||
a += 1
|
||||
a += 1
|
||||
a = a + 1
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if variable is not referenced below the op assign" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 1
|
||||
a += 1
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and a message" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
b = 2
|
||||
a = 3
|
||||
a += 1
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.last
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:5:13"
|
||||
issue.message.should eq "Useless assignment to variable `a`"
|
||||
end
|
||||
end
|
||||
|
||||
context "multi assigns" do
|
||||
it "does not report if all assigns are referenced" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a, b = {1, 2}
|
||||
a + b
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if one assign is not referenced" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a, b = {1, 2}
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.location.to_s.should eq ":3:16"
|
||||
issue.message.should eq "Useless assignment to variable `b`"
|
||||
end
|
||||
|
||||
it "reports if both assigns are reassigned and useless" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a, b = {1, 2}
|
||||
a, b = {3, 4}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if both assigns are not referenced" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a, b = {1, 2}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
|
||||
issue = s.issues.first
|
||||
issue.location.to_s.should eq ":3:13"
|
||||
issue.message.should eq "Useless assignment to variable `a`"
|
||||
|
||||
issue = s.issues.last
|
||||
issue.location.to_s.should eq ":3:16"
|
||||
issue.message.should eq "Useless assignment to variable `b`"
|
||||
end
|
||||
end
|
||||
|
||||
context "top level" do
|
||||
it "reports if assignment is not referenced" do
|
||||
s = Source.new %(
|
||||
a = 1
|
||||
a = 2
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 2
|
||||
s.issues.first.location.to_s.should eq ":2:11"
|
||||
s.issues.last.location.to_s.should eq ":3:11"
|
||||
end
|
||||
|
||||
it "doesn't report if assignments are referenced" do
|
||||
s = Source.new %(
|
||||
a = 1
|
||||
a += 1
|
||||
a
|
||||
|
||||
b, c = {1, 2}
|
||||
b
|
||||
c
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is captured by block" do
|
||||
s = Source.new %(
|
||||
a = 1
|
||||
|
||||
3.times do
|
||||
a = 2
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "branching" do
|
||||
context "if-then-else" do
|
||||
it "doesn't report if assignment is consumed by branches" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 0
|
||||
if something
|
||||
a = 1
|
||||
else
|
||||
a = 2
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is in one branch" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 0
|
||||
if something
|
||||
a = 1
|
||||
else
|
||||
nil
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is in one line branch" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 0
|
||||
a = 1 if something
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless in the branch" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
if a
|
||||
a = 2
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if only last assignment is referenced in a branch" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
a = 1
|
||||
if a
|
||||
a = 2
|
||||
a = 3
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":5:17"
|
||||
end
|
||||
|
||||
it "does not report of assignments are referenced in all branches" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
if matches
|
||||
matches = owner.lookup_matches signature
|
||||
else
|
||||
matches = owner.lookup_matches signature
|
||||
end
|
||||
|
||||
matches
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report referenced assignments in inner branches" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
has_newline = false
|
||||
|
||||
if something
|
||||
do_something unless false
|
||||
has_newline = false
|
||||
else
|
||||
do_something if true
|
||||
has_newline = true
|
||||
end
|
||||
|
||||
has_newline
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "unless-then-else" do
|
||||
it "doesn't report if assignment is consumed by branches" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 0
|
||||
unless something
|
||||
a = 1
|
||||
else
|
||||
a = 2
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if there is a useless assignment in a branch" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 0
|
||||
unless something
|
||||
a = 1
|
||||
a = 2
|
||||
else
|
||||
a = 2
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":5:17"
|
||||
end
|
||||
end
|
||||
|
||||
context "case" do
|
||||
it "does not report if assignment is referenced" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
case a
|
||||
when /foo/
|
||||
a = 1
|
||||
when /bar/
|
||||
a = 2
|
||||
end
|
||||
puts a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
case a
|
||||
when /foo/
|
||||
a = 1
|
||||
when /bar/
|
||||
a = 2
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 2
|
||||
s.issues.first.location.to_s.should eq ":5:17"
|
||||
s.issues.last.location.to_s.should eq ":7:17"
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is referenced in cond" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
case a
|
||||
when /foo/
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "binary operator" do
|
||||
it "does not report if assignment is referenced" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
(a = 1) && (b = 1)
|
||||
a + b
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
(a = 1) || (b = 1)
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":3:27"
|
||||
end
|
||||
end
|
||||
|
||||
context "while" do
|
||||
it "does not report if assignment is referenced" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
while a < 10
|
||||
a = a + 1
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
while a < 10
|
||||
b = a
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":4:17"
|
||||
end
|
||||
|
||||
it "does not report if assignment is referenced in a loop" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 3
|
||||
result = 0
|
||||
|
||||
while result < 10
|
||||
result += a
|
||||
a = a + 1
|
||||
end
|
||||
result
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if assignment is referenced as param in a loop" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
result = 0
|
||||
|
||||
while result < 10
|
||||
result += a
|
||||
a = a + 1
|
||||
end
|
||||
result
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "does not report if assignment is referenced in loop and inner branch" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
result = 0
|
||||
|
||||
while result < 10
|
||||
result += a
|
||||
if result > 0
|
||||
a = a + 1
|
||||
else
|
||||
a = 3
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "works properly if there is branch with blank node" do
|
||||
s = Source.new %(
|
||||
def visit
|
||||
count = 0
|
||||
while true
|
||||
break if count == 1
|
||||
case something
|
||||
when :any
|
||||
else
|
||||
:anything_else
|
||||
end
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "until" do
|
||||
it "does not report if assignment is referenced" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
until a > 10
|
||||
a = a + 1
|
||||
end
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
until a > 10
|
||||
b = a + 1
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":4:17"
|
||||
end
|
||||
end
|
||||
|
||||
context "exception handler" do
|
||||
it "does not report if assignment is referenced in body" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
a = 2
|
||||
rescue
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is referenced in ensure" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
a = 2
|
||||
ensure
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is referenced in else" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
a = 2
|
||||
rescue
|
||||
else
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is useless" do
|
||||
s = Source.new %(
|
||||
def method(a)
|
||||
rescue
|
||||
a = 2
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
s.issues.size.should eq 1
|
||||
s.issues.first.location.to_s.should eq ":4:15"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "macro" do
|
||||
it "doesn't report if assignment is referenced in macro" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
{% if flag?(:bits64) %}
|
||||
a.to_s
|
||||
{% else %}
|
||||
a
|
||||
{% end %}
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report referenced assignments in macro literal" do
|
||||
s = Source.new %(
|
||||
def method
|
||||
a = 2
|
||||
{% if flag?(:bits64) %}
|
||||
a = 3
|
||||
{% else %}
|
||||
a = 4
|
||||
{% end %}
|
||||
puts a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is referenced in macro def" do
|
||||
s = Source.new %(
|
||||
macro macro_call
|
||||
puts x
|
||||
end
|
||||
|
||||
def foo
|
||||
x = 1
|
||||
macro_call
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "reports if assignment is referenced in macro def in a different scope" do
|
||||
s = Source.new %(
|
||||
class Foo
|
||||
def foo
|
||||
x = 1
|
||||
end
|
||||
end
|
||||
|
||||
class Bar
|
||||
macro macro_call
|
||||
puts x
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if assignment is referenced in a macro below" do
|
||||
s = Source.new %(
|
||||
class Foo
|
||||
def foo
|
||||
a = 1
|
||||
macro_call
|
||||
end
|
||||
|
||||
macro macro_call
|
||||
puts a
|
||||
end
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "uninitialized" do
|
||||
it "reports if uninitialized assignment is not referenced at a top level" do
|
||||
s = Source.new %(
|
||||
a = uninitialized U
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports if uninitialized assignment is not referenced in a method" do
|
||||
s = Source.new %(
|
||||
def foo
|
||||
a = uninitialized U
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "doesn't report if uninitialized assignment is referenced" do
|
||||
s = Source.new %(
|
||||
def foo
|
||||
a = uninitialized U
|
||||
a
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
45
spec/ameba/rule/lint/useless_condition_in_when_spec.cr
Normal file
45
spec/ameba/rule/lint/useless_condition_in_when_spec.cr
Normal file
|
@ -0,0 +1,45 @@
|
|||
require "../../../spec_helper"
|
||||
|
||||
module Ameba::Rule::Lint
|
||||
subject = UselessConditionInWhen.new
|
||||
|
||||
describe UselessConditionInWhen do
|
||||
it "passes if there is not useless condition" do
|
||||
s = Source.new %(
|
||||
case
|
||||
when utc?
|
||||
io << " UTC"
|
||||
when local?
|
||||
Format.new(" %:z").format(self, io) if utc?
|
||||
end
|
||||
)
|
||||
subject.catch(s).should be_valid
|
||||
end
|
||||
|
||||
it "fails if there is useless if condition" do
|
||||
s = Source.new %(
|
||||
case
|
||||
when utc?
|
||||
io << " UTC" if utc?
|
||||
end
|
||||
)
|
||||
subject.catch(s).should_not be_valid
|
||||
end
|
||||
|
||||
it "reports rule, location and message" do
|
||||
s = Source.new %(
|
||||
case
|
||||
when String
|
||||
puts "hello"
|
||||
when can_generate?
|
||||
generate if can_generate?
|
||||
end
|
||||
), "source.cr"
|
||||
subject.catch(s).should_not be_valid
|
||||
issue = s.issues.first
|
||||
issue.rule.should_not be_nil
|
||||
issue.location.to_s.should eq "source.cr:6:23"
|
||||
issue.message.should eq "Useless condition in when detected"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue