Merge pull request #261 from crystal-ameba/convert-more-specs-to-use-assertion-helpers

Convert more specs to use assertion helpers
This commit is contained in:
Sijawusz Pur Rahnama 2022-04-05 00:24:19 +02:00 committed by GitHub
commit 348406b7d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 238 additions and 378 deletions

View file

@ -6,13 +6,15 @@ module Ameba::Rule::Layout
describe LineLength do describe LineLength do
it "passes if all lines are shorter than MaxLength symbols" do it "passes if all lines are shorter than MaxLength symbols" do
source = Source.new "short line" expect_no_issues subject, <<-CRYSTAL
subject.catch(source).should be_valid short line
CRYSTAL
end end
it "passes if line consists of MaxLength symbols" do it "passes if line consists of MaxLength symbols" do
source = Source.new "*" * subject.max_length expect_no_issues subject, <<-CRYSTAL
subject.catch(source).should be_valid #{"*" * subject.max_length}
CRYSTAL
end end
it "fails if there is at least one line longer than MaxLength symbols" do it "fails if there is at least one line longer than MaxLength symbols" do
@ -33,10 +35,10 @@ module Ameba::Rule::Layout
context "properties" do context "properties" do
it "allows to configure max length of the line" do it "allows to configure max length of the line" do
source = Source.new long_line
rule = LineLength.new rule = LineLength.new
rule.max_length = long_line.size rule.max_length = long_line.size
rule.catch(source).should be_valid
expect_no_issues rule, long_line
end end
end end
end end

View file

@ -6,163 +6,115 @@ module Ameba::Rule::Lint
context "when using `-`" do context "when using `-`" do
it "registers an offense with `x`" do it "registers an offense with `x`" do
source = Source.new("x =- y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid x =- y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `-=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `-=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "registers an offense with `@x`" do it "registers an offense with `@x`" do
source = Source.new("@x =- y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @x =- y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `-=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `-=`?"
issue.location.to_s.should eq "source.cr:1:4"
issue.end_location.to_s.should eq "source.cr:1:5"
end end
it "registers an offense with `@@x`" do it "registers an offense with `@@x`" do
source = Source.new("@@x =- y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @@x =- y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `-=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `-=`?"
issue.location.to_s.should eq "source.cr:1:5"
issue.end_location.to_s.should eq "source.cr:1:6"
end end
it "registers an offense with `X`" do it "registers an offense with `X`" do
source = Source.new("X =- y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid X =- y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `-=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `-=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "does not register an offense when no mistype assignments" do it "does not register an offense when no mistype assignments" do
subject.catch(Source.new(<<-CRYSTAL)).should be_valid expect_no_issues subject, <<-CRYSTAL
x = 1 x = 1
x -= y x -= y
x = -y x = -y
CRYSTAL CRYSTAL
end end
end end
context "when using `+`" do context "when using `+`" do
it "registers an offense with `x`" do it "registers an offense with `x`" do
source = Source.new("x =+ y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid x =+ y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `+=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `+=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "registers an offense with `@x`" do it "registers an offense with `@x`" do
source = Source.new("@x =+ y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @x =+ y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `+=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `+=`?"
issue.location.to_s.should eq "source.cr:1:4"
issue.end_location.to_s.should eq "source.cr:1:5"
end end
it "registers an offense with `@@x`" do it "registers an offense with `@@x`" do
source = Source.new("@@x =+ y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @@x =+ y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `+=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `+=`?"
issue.location.to_s.should eq "source.cr:1:5"
issue.end_location.to_s.should eq "source.cr:1:6"
end end
it "registers an offense with `X`" do it "registers an offense with `X`" do
source = Source.new("X =+ y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid X =+ y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `+=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `+=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "does not register an offense when no mistype assignments" do it "does not register an offense when no mistype assignments" do
subject.catch(Source.new(<<-CRYSTAL)).should be_valid expect_no_issues subject, <<-CRYSTAL
x = 1 x = 1
x += y x += y
x = +y x = +y
CRYSTAL CRYSTAL
end end
end end
context "when using `!`" do context "when using `!`" do
it "registers an offense with `x`" do it "registers an offense with `x`" do
source = Source.new("x =! y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid x =! y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `!=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `!=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "registers an offense with `@x`" do it "registers an offense with `@x`" do
source = Source.new("@x =! y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @x =! y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `!=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `!=`?"
issue.location.to_s.should eq "source.cr:1:4"
issue.end_location.to_s.should eq "source.cr:1:5"
end end
it "registers an offense with `@@x`" do it "registers an offense with `@@x`" do
source = Source.new("@@x =! y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid @@x =! y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `!=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `!=`?"
issue.location.to_s.should eq "source.cr:1:5"
issue.end_location.to_s.should eq "source.cr:1:6"
end end
it "registers an offense with `X`" do it "registers an offense with `X`" do
source = Source.new("X =! y", "source.cr") expect_issue subject, <<-CRYSTAL
subject.catch(source).should_not be_valid X =! y
source.issues.size.should eq 1 # ^^ error: Suspicious assignment detected. Did you mean `!=`?
CRYSTAL
issue = source.issues.first
issue.message.should eq "Suspicious assignment detected. Did you mean `!=`?"
issue.location.to_s.should eq "source.cr:1:3"
issue.end_location.to_s.should eq "source.cr:1:4"
end end
it "does not register an offense when no mistype assignments" do it "does not register an offense when no mistype assignments" do
subject.catch(Source.new(<<-CRYSTAL)).should be_valid expect_no_issues subject, <<-CRYSTAL
x = false x = false
x != y x != y
x = !y x = !y
CRYSTAL CRYSTAL
end end
end end
end end

View file

@ -5,62 +5,42 @@ module Ameba::Rule::Lint
subject = BadDirective.new subject = BadDirective.new
it "does not report if rule is correct" do it "does not report if rule is correct" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
# ameba:disable Lint/BadDirective # ameba:disable Lint/BadDirective
) CRYSTAL
subject.catch(s).should be_valid
end end
it "reports if there is incorrect action" do it "reports if there is incorrect action" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
# ameba:foo Lint/BadDirective # ameba:foo Lint/BadDirective
), "source.cr" # ^{} error: Bad action in comment directive: 'foo'. Possible values: disable, enable
subject.catch(s).should_not be_valid CRYSTAL
s.issues.size.should eq 1
issue = s.issues.first
issue.message.should eq(
"Bad action in comment directive: 'foo'. Possible values: disable, enable"
)
issue.location.to_s.should eq "source.cr:1:1"
issue.end_location.to_s.should eq ""
end end
it "reports if there are incorrect rule names" do it "reports if there are incorrect rule names" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
# ameba:enable BadRule1, BadRule2 # ameba:enable BadRule1, BadRule2
), "source.cr" # ^{} error: Such rules do not exist: BadRule1, BadRule2
subject.catch(s).should_not be_valid CRYSTAL
s.issues.size.should eq 1
issue = s.issues.first
issue.message.should eq(
"Such rules do not exist: BadRule1, BadRule2"
)
issue.location.to_s.should eq "source.cr:1:1"
issue.end_location.to_s.should eq ""
end end
it "does not report if there no action and rules at all" do it "does not report if there no action and rules at all" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
# ameba: # ameba:
) CRYSTAL
subject.catch(s).should be_valid
end end
it "does not report if there are no rules" do it "does not report if there are no rules" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
# ameba:enable # ameba:enable
# ameba:disable # ameba:disable
) CRYSTAL
subject.catch(s).should be_valid
end end
it "does not report if there are group names in the directive" do it "does not report if there are group names in the directive" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
# ameba:disable Style Performance # ameba:disable Style Performance
) CRYSTAL
subject.catch(s).should be_valid
end end
end end
end end

View file

@ -5,7 +5,7 @@ module Ameba::Rule::Lint
subject = EmptyLoop.new subject = EmptyLoop.new
it "does not report if there are not empty loops" do it "does not report if there are not empty loops" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
a = 1 a = 1
while a < 10 while a < 10
@ -19,54 +19,50 @@ module Ameba::Rule::Lint
loop do loop do
a += 1 a += 1
end end
) CRYSTAL
subject.catch(s).should be_valid
end end
it "reports if there is an empty while loop" do it "reports if there is an empty while loop" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
a = 1 a = 1
while true while true
# ^^^^^^^^ error: Empty loop detected
end end
) CRYSTAL
subject.catch(s).should_not be_valid
end end
it "doesn't report if while loop has non-literals in cond block" do it "doesn't report if while loop has non-literals in cond block" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
a = 1 a = 1
while a = gets.to_s while a = gets.to_s
# nothing here # nothing here
end end
) CRYSTAL
subject.catch(s).should be_valid
end end
it "reports if there is an empty until loop" do it "reports if there is an empty until loop" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
do_something do_something
until false until false
# ^^^^^^^^^ error: Empty loop detected
end end
) CRYSTAL
subject.catch(s).should_not be_valid
end end
it "doesn't report if until loop has non-literals in cond block" do it "doesn't report if until loop has non-literals in cond block" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
until socket_open? until socket_open?
end end
) CRYSTAL
subject.catch(s).should be_valid
end end
it "reports if there an empty loop" do it "reports if there an empty loop" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
a = 1 a = 1
loop do loop do
# ^^^^^ error: Empty loop detected
end end
) CRYSTAL
subject.catch(s).should_not be_valid
end end
it "reports rule, message and location" do it "reports rule, message and location" do

View file

@ -5,26 +5,32 @@ module Ameba::Rule::Lint
subject = HashDuplicatedKey.new subject = HashDuplicatedKey.new
it "passes if there is no duplicated keys in a hash literals" do it "passes if there is no duplicated keys in a hash literals" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
h = {"a" => 1, :a => 2, "b" => 3} h = {"a" => 1, :a => 2, "b" => 3}
h = {"a" => 1, "b" => 2, "c" => {"a" => 3, "b" => 4}} h = {"a" => 1, "b" => 2, "c" => {"a" => 3, "b" => 4}}
h = {} of String => String h = {} of String => String
) CRYSTAL
subject.catch(s).should be_valid
end end
it "fails if there is a duplicated key in a hash literal" do it "fails if there is a duplicated key in a hash literal" do
s = Source.new %q( expect_issue subject, <<-CRYSTAL
h = {"a" => 1, "b" => 2, "a" => 3} h = {"a" => 1, "b" => 2, "a" => 3}
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated keys in hash literal: "a"
subject.catch(s).should_not be_valid CRYSTAL
end end
it "fails if there is a duplicated key in the inner hash literal" do it "fails if there is a duplicated key in the inner hash literal" do
s = Source.new %q( expect_issue subject, <<-CRYSTAL
h = {"a" => 1, "b" => {"a" => 3, "b" => 4, "a" => 5}} h = {"a" => 1, "b" => {"a" => 3, "b" => 4, "a" => 5}}
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated keys in hash literal: "a"
subject.catch(s).should_not be_valid CRYSTAL
end
it "reports multiple duplicated keys" do
expect_issue subject, <<-CRYSTAL
h = {"key1" => 1, "key1" => 2, "key2" => 3, "key2" => 4}
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated keys in hash literal: "key1", "key2"
CRYSTAL
end end
it "reports rule, location and message" do it "reports rule, location and message" do
@ -38,14 +44,5 @@ module Ameba::Rule::Lint
issue.end_location.to_s.should eq "source.cr:1:24" issue.end_location.to_s.should eq "source.cr:1:24"
issue.message.should eq %(Duplicated keys in hash literal: "a") issue.message.should eq %(Duplicated keys in hash literal: "a")
end 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
end end

View file

@ -5,15 +5,14 @@ module Ameba::Rule::Lint
describe LiteralInInterpolation do describe LiteralInInterpolation do
it "passes with good interpolation examples" do it "passes with good interpolation examples" do
s = Source.new %q( expect_no_issues subject, <<-CRYSTAL
name = "Ary" name = "Ary"
"Hello, #{name}" "Hello, #{name}"
"#{name}" "#{name}"
"Name size: #{name.size}" "Name size: #{name.size}"
) CRYSTAL
subject.catch(s).should be_valid
end end
it "fails if there is useless interpolation" do it "fails if there is useless interpolation" do

View file

@ -5,22 +5,25 @@ module Ameba::Rule::Lint
subject = RandZero.new subject = RandZero.new
it "passes if it is not rand(1) or rand(0)" do it "passes if it is not rand(1) or rand(0)" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
rand(1.0) rand(1.0)
rand(0.11) rand(0.11)
rand(2) rand(2)
) CRYSTAL
subject.catch(s).should be_valid
end end
it "fails if it is rand(0)" do it "fails if it is rand(0)" do
s = Source.new "rand(0)" expect_issue subject, <<-CRYSTAL
subject.catch(s).should_not be_valid rand(0)
# ^^^^^ error: rand(0) always returns 0
CRYSTAL
end end
it "fails if it is rand(1)" do it "fails if it is rand(1)" do
s = Source.new "rand(1)" expect_issue subject, <<-CRYSTAL
subject.catch(s).should_not be_valid rand(1)
# ^^^^^ error: rand(1) always returns 0
CRYSTAL
end end
it "reports rule, location and a message" do it "reports rule, location and a message" do

View file

@ -5,23 +5,22 @@ module Ameba::Rule::Lint
subject = Syntax.new subject = Syntax.new
it "passes if there is no invalid syntax" do it "passes if there is no invalid syntax" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
def hello def hello
puts "totally valid" puts "totally valid"
rescue e: Exception rescue e: Exception
end end
) CRYSTAL
subject.catch(s).should be_valid
end end
it "fails if there is an invalid syntax" do it "fails if there is an invalid syntax" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
def hello def hello
puts "invalid" puts "invalid"
rescue Exception => e rescue Exception => e
# ^ error: expecting any of these tokens: ;, NEWLINE (not '=>')
end end
) CRYSTAL
subject.catch(s).should_not be_valid
end end
it "reports rule, location and message" do it "reports rule, location and message" do

View file

@ -5,17 +5,15 @@ module Ameba::Rule::Lint
subject = UnneededDisableDirective.new subject = UnneededDisableDirective.new
it "passes if there are no comments" do it "passes if there are no comments" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
a = 1 a = 1
) CRYSTAL
subject.catch(s).should be_valid
end end
it "passes if there is disable directive" do it "passes if there is disable directive" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
a = 1 # my super var a = 1 # my super var
) CRYSTAL
subject.catch(s).should be_valid
end end
it "doesn't report if there is disable directive and it is needed" do it "doesn't report if there is disable directive and it is needed" do
@ -48,33 +46,27 @@ module Ameba::Rule::Lint
end end
it "fails if there is unneeded directive" do it "fails if there is unneeded directive" do
s = Source.new %Q( expect_issue subject, <<-CRYSTAL
# ameba:disable #{NamedRule.name} # ameba:disable #{NamedRule.name}
# ^{} error: Unnecessary disabling of #{NamedRule.name}
a = 1 a = 1
) CRYSTAL
subject.catch(s).should_not be_valid
s.issues.first.message.should eq(
"Unnecessary disabling of #{NamedRule.name}"
)
end end
it "fails if there is inline unneeded directive" do it "fails if there is inline unneeded directive" do
s = Source.new %Q(a = 1 # ameba:disable #{NamedRule.name}) expect_issue subject, <<-CRYSTAL
subject.catch(s).should_not be_valid a = 1 # ameba:disable #{NamedRule.name}
s.issues.first.message.should eq( # ^ error: Unnecessary disabling of #{NamedRule.name}
"Unnecessary disabling of #{NamedRule.name}" CRYSTAL
)
end end
it "detects mixed inline directives" do it "detects mixed inline directives" do
s = Source.new %Q( expect_issue subject, <<-CRYSTAL
# ameba:disable Rule1, Rule2 # ameba:disable Rule1, Rule2
# ^{} error: Unnecessary disabling of Rule1, Rule2
a = 1 # ameba:disable Rule3 a = 1 # ameba:disable Rule3
), "source.cr" # ^ error: Unnecessary disabling of Rule3
subject.catch(s).should_not be_valid CRYSTAL
s.issues.size.should eq 2
s.issues.first.message.should contain "Rule1, Rule2"
s.issues.last.message.should contain "Rule3"
end end
it "fails if there is disabled UnneededDisableDirective" do it "fails if there is disabled UnneededDisableDirective" do

View file

@ -5,25 +5,24 @@ module Ameba::Rule::Lint
describe UselessConditionInWhen do describe UselessConditionInWhen do
it "passes if there is not useless condition" do it "passes if there is not useless condition" do
s = Source.new %( expect_no_issues subject, <<-CRYSTAL
case case
when utc? when utc?
io << " UTC" io << " UTC"
when local? when local?
Format.new(" %:z").format(self, io) if utc? Format.new(" %:z").format(self, io) if utc?
end end
) CRYSTAL
subject.catch(s).should be_valid
end end
it "fails if there is useless if condition" do it "fails if there is useless if condition" do
s = Source.new %( expect_issue subject, <<-CRYSTAL
case case
when utc? when utc?
io << " UTC" if utc? io << " UTC" if utc?
# ^^^^ error: Useless condition in when detected
end end
) CRYSTAL
subject.catch(s).should_not be_valid
end end
it "reports rule, location and message" do it "reports rule, location and message" do

View file

@ -15,33 +15,35 @@ module Ameba::Rule::Metrics
end end
end end
end end
CODE CODE
describe CyclomaticComplexity do describe CyclomaticComplexity do
it "passes for empty methods" do it "passes for empty methods" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
def hello def hello
end end
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports one issue for a complex method" do it "reports one issue for a complex method" do
subject.max_complexity = 5 rule = CyclomaticComplexity.new
rule.max_complexity = 5
source = Source.new(complex_method, "source.cr") source = Source.new(complex_method, "source.cr")
subject.catch(source).should_not be_valid rule.catch(source).should_not be_valid
issue = source.issues.first issue = source.issues.first
issue.rule.should eq subject issue.rule.should eq rule
issue.location.to_s.should eq "source.cr:1:5" issue.location.to_s.should eq "source.cr:1:5"
issue.end_location.to_s.should eq "source.cr:1:9" issue.end_location.to_s.should eq "source.cr:1:9"
issue.message.should eq "Cyclomatic complexity too high [8/5]" issue.message.should eq "Cyclomatic complexity too high [8/5]"
end end
it "doesn't report an issue for an increased threshold" do it "doesn't report an issue for an increased threshold" do
subject.max_complexity = 100 rule = CyclomaticComplexity.new
source = Source.new(complex_method, "source.cr") rule.max_complexity = 100
subject.catch(source).should be_valid
expect_no_issues rule, complex_method
end end
end end
end end

View file

@ -49,6 +49,7 @@ module Ameba::Rule::Performance
it "allows to configure object_call_names" do it "allows to configure object_call_names" do
rule = Rule::Performance::AnyAfterFilter.new rule = Rule::Performance::AnyAfterFilter.new
rule.filter_names = %w(select) rule.filter_names = %w(select)
expect_no_issues rule, <<-CRYSTAL expect_no_issues rule, <<-CRYSTAL
[1, 2, 3].reject { |e| e > 2 }.any? [1, 2, 3].reject { |e| e > 2 }.any?
CRYSTAL CRYSTAL

View file

@ -47,6 +47,7 @@ module Ameba::Rule::Performance
it "allows to configure `call_names`" do it "allows to configure `call_names`" do
rule = ChainedCallWithNoBang.new rule = ChainedCallWithNoBang.new
rule.call_names = %w(uniq) rule.call_names = %w(uniq)
expect_no_issues rule, <<-CRYSTAL expect_no_issues rule, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.reverse [1, 2, 3].select { |e| e > 2 }.reverse
CRYSTAL CRYSTAL

View file

@ -5,39 +5,35 @@ module Ameba::Rule::Performance
describe CompactAfterMap do describe CompactAfterMap do
it "passes if there is no potential performance improvements" do it "passes if there is no potential performance improvements" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
(1..3).compact_map(&.itself) (1..3).compact_map(&.itself)
) CRYSTAL
subject.catch(source).should be_valid
end end
it "passes if there is map followed by a bang call" do it "passes if there is map followed by a bang call" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
(1..3).map(&.itself).compact! (1..3).map(&.itself).compact!
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is map followed by compact call" do it "reports if there is map followed by compact call" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
(1..3).map(&.itself).compact (1..3).map(&.itself).compact
) # ^^^^^^^^^^^^^^^^^^^^^^ error: Use `compact_map {...}` instead of `map {...}.compact`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if source is a spec" do it "does not report if source is a spec" do
source = Source.new %( expect_no_issues subject, path: "source_spec.cr", code: <<-CRYSTAL
(1..3).map(&.itself).compact (1..3).map(&.itself).compact
), "source_spec.cr" CRYSTAL
subject.catch(source).should be_valid
end end
context "macro" do context "macro" do
it "doesn't report in macro scope" do it "doesn't report in macro scope" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
{{ [1, 2, 3].map(&.to_s).compact }} {{ [1, 2, 3].map(&.to_s).compact }}
) CRYSTAL
subject.catch(source).should be_valid
end end
end end

View file

@ -5,74 +5,70 @@ module Ameba::Rule::Performance
describe FirstLastAfterFilter do describe FirstLastAfterFilter do
it "passes if there is no potential performance improvements" do it "passes if there is no potential performance improvements" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 1 } [1, 2, 3].select { |e| e > 1 }
[1, 2, 3].reverse.select { |e| e > 1 } [1, 2, 3].reverse.select { |e| e > 1 }
[1, 2, 3].reverse.last [1, 2, 3].reverse.last
[1, 2, 3].reverse.first [1, 2, 3].reverse.first
[1, 2, 3].reverse.first [1, 2, 3].reverse.first
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is select followed by last" do it "reports if there is select followed by last" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.last [1, 2, 3].select { |e| e > 2 }.last
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `reverse_each.find {...}` instead of `select {...}.last`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if source is a spec" do it "does not report if source is a spec" do
source = Source.new %( expect_no_issues subject, path: "source_spec.cr", code: <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.last [1, 2, 3].select { |e| e > 2 }.last
), "source_spec.cr" CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is select followed by last?" do it "reports if there is select followed by last?" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.last? [1, 2, 3].select { |e| e > 2 }.last?
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `reverse_each.find {...}` instead of `select {...}.last?`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "reports if there is select followed by first" do it "reports if there is select followed by first" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.first [1, 2, 3].select { |e| e > 2 }.first
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `find {...}` instead of `select {...}.first`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if there is selected followed by first with arguments" do it "does not report if there is selected followed by first with arguments" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
[1, 2, 3].select { |n| n % 2 == 0 }.first(2) [1, 2, 3].select { |n| n % 2 == 0 }.first(2)
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is select followed by first?" do it "reports if there is select followed by first?" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.first? [1, 2, 3].select { |e| e > 2 }.first?
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `find {...}` instead of `select {...}.first?`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if there is select followed by any other call" do it "does not report if there is select followed by any other call" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.size [1, 2, 3].select { |e| e > 2 }.size
[1, 2, 3].select { |e| e > 2 }.any? [1, 2, 3].select { |e| e > 2 }.any?
) CRYSTAL
subject.catch(source).should be_valid
end end
context "properties" do context "properties" do
it "allows to configure object_call_names" do it "allows to configure object_call_names" do
source = Source.new %(
[1, 2, 3].select { |e| e > 2 }.first
)
rule = Rule::Performance::FirstLastAfterFilter.new rule = Rule::Performance::FirstLastAfterFilter.new
rule.filter_names = %w(reject) rule.filter_names = %w(reject)
rule.catch(source).should be_valid
expect_no_issues rule, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.first
CRYSTAL
end end
end end
@ -91,58 +87,12 @@ module Ameba::Rule::Performance
issue.message.should eq "Use `find {...}` instead of `select {...}.first`" issue.message.should eq "Use `find {...}` instead of `select {...}.first`"
end end
it "reports a correct message for first?" do
s = Source.new %(
[1, 2, 3].select { |e| e > 2 }.first?
), "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:1:11"
issue.end_location.to_s.should eq "source.cr:1:38"
issue.message.should eq "Use `find {...}` instead of `select {...}.first?`"
end
it "reports rule, pos and reverse message" do
s = Source.new %(
[1, 2, 3].select { |e| e > 2 }.last
), "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:1:11"
issue.end_location.to_s.should eq "source.cr:1:36"
issue.message.should eq "Use `reverse_each.find {...}` instead of `select {...}.last`"
end
context "macro" do context "macro" do
it "doesn't report in macro scope" do it "doesn't report in macro scope" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
{{[1, 2, 3].select { |e| e > 2 }.last }} {{ [1, 2, 3].select { |e| e > 2 }.last }}
) CRYSTAL
subject.catch(source).should be_valid
end end
end end
it "reports a correct message for last?" do
s = Source.new %(
[1, 2, 3].select { |e| e > 2 }.last?
), "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:1:11"
issue.end_location.to_s.should eq "source.cr:1:37"
issue.message.should eq "Use `reverse_each.find {...}` instead of `select {...}.last?`"
end
end end
end end

View file

@ -5,32 +5,29 @@ module Ameba::Rule::Performance
describe FlattenAfterMap do describe FlattenAfterMap do
it "passes if there is no potential performance improvements" do it "passes if there is no potential performance improvements" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
%w[Alice Bob].flat_map(&.chars) %w[Alice Bob].flat_map(&.chars)
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is map followed by flatten call" do it "reports if there is map followed by flatten call" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
%w[Alice Bob].map(&.chars).flatten %w[Alice Bob].map(&.chars).flatten
) # ^^^^^^^^^^^^^^^^^^^^^ error: Use `flat_map {...}` instead of `map {...}.flatten`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report is source is a spec" do it "does not report is source is a spec" do
source = Source.new %( expect_no_issues subject, path: "source_spec.cr", code: <<-CRYSTAL
%w[Alice Bob].map(&.chars).flatten %w[Alice Bob].map(&.chars).flatten
), "source_spec.cr" CRYSTAL
subject.catch(source).should be_valid
end end
context "macro" do context "macro" do
it "doesn't report in macro scope" do it "doesn't report in macro scope" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
{{ %w[Alice Bob].map(&.chars).flatten }} {{ %w[Alice Bob].map(&.chars).flatten }}
) CRYSTAL
subject.catch(source).should be_valid
end end
end end

View file

@ -5,47 +5,44 @@ module Ameba::Rule::Performance
describe MapInsteadOfBlock do describe MapInsteadOfBlock do
it "passes if there is no potential performance improvements" do it "passes if there is no potential performance improvements" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
(1..3).sum(&.*(2)) (1..3).sum(&.*(2))
(1..3).product(&.*(2)) (1..3).product(&.*(2))
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is map followed by sum without a block" do it "reports if there is map followed by sum without a block" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
(1..3).map(&.to_u64).sum (1..3).map(&.to_u64).sum
) # ^^^^^^^^^^^^^^^^^^ error: Use `sum {...}` instead of `map {...}.sum`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if source is a spec" do it "does not report if source is a spec" do
source = Source.new %( expect_no_issues subject, path: "source_spec.cr", code: <<-CRYSTAL
(1..3).map(&.to_s).join (1..3).map(&.to_s).join
), "source_spec.cr" CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is map followed by sum without a block (with argument)" do it "reports if there is map followed by sum without a block (with argument)" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
(1..3).map(&.to_u64).sum(0) (1..3).map(&.to_u64).sum(0)
) # ^^^^^^^^^^^^^^^^^^ error: Use `sum {...}` instead of `map {...}.sum`
subject.catch(source).should_not be_valid CRYSTAL
end end
it "reports if there is map followed by sum with a block" do it "reports if there is map followed by sum with a block" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
(1..3).map(&.to_u64).sum(&.itself) (1..3).map(&.to_u64).sum(&.itself)
) # ^^^^^^^^^^^^^^^^^^ error: Use `sum {...}` instead of `map {...}.sum`
subject.catch(source).should_not be_valid CRYSTAL
end end
context "macro" do context "macro" do
it "doesn't report in macro scope" do it "doesn't report in macro scope" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
{{ [1, 2, 3].map(&.to_u64).sum }} {{ [1, 2, 3].map(&.to_u64).sum }}
) CRYSTAL
subject.catch(source).should be_valid
end end
end end

View file

@ -5,7 +5,7 @@ module Ameba::Rule::Performance
describe SizeAfterFilter do describe SizeAfterFilter do
it "passes if there is no potential performance improvements" do it "passes if there is no potential performance improvements" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 } [1, 2, 3].select { |e| e > 2 }
[1, 2, 3].reject { |e| e < 2 } [1, 2, 3].reject { |e| e < 2 }
[1, 2, 3].count { |e| e > 2 && e.odd? } [1, 2, 3].count { |e| e > 2 && e.odd? }
@ -13,55 +13,52 @@ module Ameba::Rule::Performance
User.select("field AS name").count User.select("field AS name").count
Company.select(:value).count Company.select(:value).count
) CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is a select followed by size" do it "reports if there is a select followed by size" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.size [1, 2, 3].select { |e| e > 2 }.size
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `count {...}` instead of `select {...}.size`.
subject.catch(source).should_not be_valid CRYSTAL
end end
it "does not report if source is a spec" do it "does not report if source is a spec" do
source = Source.new %( expect_no_issues subject, path: "source_spec.cr", code: <<-CRYSTAL
[1, 2, 3].select { |e| e > 2 }.size [1, 2, 3].select { |e| e > 2 }.size
), "source_spec.cr" CRYSTAL
subject.catch(source).should be_valid
end end
it "reports if there is a reject followed by size" do it "reports if there is a reject followed by size" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].reject { |e| e < 2 }.size [1, 2, 3].reject { |e| e < 2 }.size
) # ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Use `count {...}` instead of `reject {...}.size`.
subject.catch(source).should_not be_valid CRYSTAL
end end
it "reports if a block shorthand used" do it "reports if a block shorthand used" do
source = Source.new %( expect_issue subject, <<-CRYSTAL
[1, 2, 3].reject(&.empty?).size [1, 2, 3].reject(&.empty?).size
) # ^^^^^^^^^^^^^^^^^^^^^^ error: Use `count {...}` instead of `reject {...}.size`.
subject.catch(source).should_not be_valid CRYSTAL
end end
context "properties" do context "properties" do
it "allows to configure object caller names" do it "allows to configure object caller names" do
source = Source.new %(
[1, 2, 3].reject(&.empty?).size
)
rule = Rule::Performance::SizeAfterFilter.new rule = Rule::Performance::SizeAfterFilter.new
rule.filter_names = %w(select) rule.filter_names = %w(select)
rule.catch(source).should be_valid
expect_no_issues rule, <<-CRYSTAL
[1, 2, 3].reject(&.empty?).size
CRYSTAL
end end
end end
context "macro" do context "macro" do
it "doesn't report in macro scope" do it "doesn't report in macro scope" do
source = Source.new %( expect_no_issues subject, <<-CRYSTAL
{{[1, 2, 3].select { |v| v > 1 }.size}} {{[1, 2, 3].select { |v| v > 1 }.size}}
) CRYSTAL
subject.catch(source).should be_valid
end end
end end