Add tests for AST::Util#control_exp_code

This commit is contained in:
fn ⌃ ⌥ 2021-11-09 11:45:38 -08:00
parent c9ba487373
commit 01dfcbe76a
4 changed files with 56 additions and 33 deletions

View file

@ -39,31 +39,31 @@ module Ameba::AST
describe "#node_source" do describe "#node_source" do
it "returns original source of the node" do it "returns original source of the node" do
s = %( s = <<-CRYSTAL
a = 1 a = 1
) CRYSTAL
node = Crystal::Parser.new(s).parse node = Crystal::Parser.new(s).parse
source = subject.node_source node, s.split("\n") source = subject.node_source node, s.split("\n")
source.should eq "a = 1" source.should eq "a = 1"
end end
it "returns original source of multiline node" do it "returns original source of multiline node" do
s = %( s = <<-CRYSTAL
if () if ()
:ok :ok
end end
) CRYSTAL
node = Crystal::Parser.new(s).parse node = Crystal::Parser.new(s).parse
source = subject.node_source node, s.split("\n") source = subject.node_source node, s.split("\n")
source.should eq <<-CRYSTAL source.should eq <<-CRYSTAL
if () if ()
:ok :ok
end end
CRYSTAL CRYSTAL
end end
it "does not report source of node which has incorrect location" do it "does not report source of node which has incorrect location" do
s = %q( s = <<-'CRYSTAL'
module MyModule module MyModule
macro conditional_error_for_inline_callbacks macro conditional_error_for_inline_callbacks
\{% \{%
@ -74,7 +74,7 @@ module Ameba::AST
macro before_save(x = nil) macro before_save(x = nil)
end end
end end
) CRYSTAL
node = as_nodes(s).nil_literal_nodes.first node = as_nodes(s).nil_literal_nodes.first
source = subject.node_source node, s.split("\n") source = subject.node_source node, s.split("\n")
@ -140,29 +140,29 @@ module Ameba::AST
end end
it "returns true if this is if-else consumed by flow expressions" do it "returns true if this is if-else consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
if foo if foo
return :foo return :foo
else else
return :bar return :bar
end end
) CRYSTAL
subject.flow_expression?(node, false).should eq true subject.flow_expression?(node, false).should eq true
end end
it "returns true if this is unless-else consumed by flow expressions" do it "returns true if this is unless-else consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
unless foo unless foo
return :foo return :foo
else else
return :bar return :bar
end end
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns true if this is case consumed by flow expressions" do it "returns true if this is case consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
case case
when 1 when 1
return 1 return 1
@ -171,71 +171,71 @@ module Ameba::AST
else else
return 3 return 3
end end
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns true if this is exception handler consumed by flow expressions" do it "returns true if this is exception handler consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
begin begin
raise "exp" raise "exp"
rescue e rescue e
return e return e
end end
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns true if this while consumed by flow expressions" do it "returns true if this while consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
while true while true
return return
end end
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns false if this while with break" do it "returns false if this while with break" do
node = as_node %( node = as_node <<-CRYSTAL
while true while true
break break
end end
) CRYSTAL
subject.flow_expression?(node).should eq false subject.flow_expression?(node).should eq false
end end
it "returns true if this until consumed by flow expressions" do it "returns true if this until consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
until false until false
return return
end end
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns false if this until with break" do it "returns false if this until with break" do
node = as_node %( node = as_node <<-CRYSTAL
until false until false
break break
end end
) CRYSTAL
subject.flow_expression?(node).should eq false subject.flow_expression?(node).should eq false
end end
it "returns true if this expressions consumed by flow expressions" do it "returns true if this expressions consumed by flow expressions" do
node = as_node %( node = as_node <<-CRYSTAL
exp1 exp1
exp2 exp2
return return
) CRYSTAL
subject.flow_expression?(node).should eq true subject.flow_expression?(node).should eq true
end end
it "returns false otherwise" do it "returns false otherwise" do
node = as_node %( node = as_node <<-CRYSTAL
exp1 exp1
exp2 exp2
) CRYSTAL
subject.flow_expression?(node).should eq false subject.flow_expression?(node).should eq false
end end
end end
@ -322,5 +322,28 @@ module Ameba::AST
subject.loop?(node).should eq false subject.loop?(node).should eq false
end end
end end
describe "#control_exp_code" do
it "returns the exp code of a control expression" do
s = "return 1"
node = as_node(s).as Crystal::ControlExpression
exp_code = subject.control_exp_code node, [s]
exp_code.should eq "1"
end
it "wraps implicit tuple literal with curly brackets" do
s = "return 1, 2"
node = as_node(s).as Crystal::ControlExpression
exp_code = subject.control_exp_code node, [s]
exp_code.should eq "{1, 2}"
end
it "accepts explicit tuple literal" do
s = "return {1, 2}"
node = as_node(s).as Crystal::ControlExpression
exp_code = subject.control_exp_code node, [s]
exp_code.should eq "{1, 2}"
end
end
end end
end end

View file

@ -161,13 +161,13 @@ module Ameba::AST::Util
# Returns the exp code of a control expression. # Returns the exp code of a control expression.
# Wraps implicit tuple literal with curly brackets (e.g. multi-return). # Wraps implicit tuple literal with curly brackets (e.g. multi-return).
def control_exp_code(source, node : Crystal::ControlExpression) def control_exp_code(node : Crystal::ControlExpression, code_lines)
return unless (exp = node.exp) return unless (exp = node.exp)
return unless (exp_code = node_source(exp, source.lines)) return unless (exp_code = node_source(exp, code_lines))
return exp_code unless exp.is_a?(Crystal::TupleLiteral) && exp_code[0] != '{' return exp_code unless exp.is_a?(Crystal::TupleLiteral) && exp_code[0] != '{'
return unless (exp_start = exp.elements.first.location) return unless (exp_start = exp.elements.first.location)
return unless (exp_end = exp.end_location) return unless (exp_end = exp.end_location)
"{#{source_between(exp_start, exp_end, source.lines)}}" "{#{source_between(exp_start, exp_end, code_lines)}}"
end end
end end

View file

@ -116,7 +116,7 @@ module Ameba::Rule::Style
return if allow_multi_next && node.exp.is_a?(Crystal::TupleLiteral) return if allow_multi_next && node.exp.is_a?(Crystal::TupleLiteral)
return if allow_empty_next && (node.exp.nil? || node.exp.not_nil!.nop?) return if allow_empty_next && (node.exp.nil? || node.exp.not_nil!.nop?)
if (exp_code = control_exp_code(source, node)) if (exp_code = control_exp_code(node, source.lines))
issue_for node, MSG do |corrector| issue_for node, MSG do |corrector|
corrector.replace(node, exp_code) corrector.replace(node, exp_code)
end end

View file

@ -113,7 +113,7 @@ module Ameba::Rule::Style
return if allow_multi_return && node.exp.is_a?(Crystal::TupleLiteral) return if allow_multi_return && node.exp.is_a?(Crystal::TupleLiteral)
return if allow_empty_return && (node.exp.nil? || node.exp.not_nil!.nop?) return if allow_empty_return && (node.exp.nil? || node.exp.not_nil!.nop?)
if (exp_code = control_exp_code(source, node)) if (exp_code = control_exp_code(node, source.lines))
issue_for node, MSG do |corrector| issue_for node, MSG do |corrector|
corrector.replace(node, exp_code) corrector.replace(node, exp_code)
end end