mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Raise error if infinite correction loop
This commit is contained in:
parent
16608965f5
commit
437584f9db
3 changed files with 277 additions and 7 deletions
|
@ -8,6 +8,13 @@ module Ameba
|
|||
|
||||
config.update_rule ErrorRule.rule_name, enabled: false
|
||||
config.update_rule PerfRule.rule_name, enabled: false
|
||||
config.update_rule AtoAA.rule_name, enabled: false
|
||||
config.update_rule AtoB.rule_name, enabled: false
|
||||
config.update_rule BtoA.rule_name, enabled: false
|
||||
config.update_rule BtoC.rule_name, enabled: false
|
||||
config.update_rule CtoA.rule_name, enabled: false
|
||||
config.update_rule ClassToModule.rule_name, enabled: false
|
||||
config.update_rule ModuleToClass.rule_name, enabled: false
|
||||
|
||||
Runner.new(config)
|
||||
end
|
||||
|
@ -54,6 +61,15 @@ module Ameba
|
|||
Runner.new(all_rules, [source], formatter, default_severity).run.success?.should be_true
|
||||
end
|
||||
|
||||
it "aborts because of an infinite loop" do
|
||||
rules = [AtoAA.new] of Rule::Base
|
||||
source = Source.new "class A; end", "source.cr"
|
||||
message = "Infinite loop in source.cr caused by Ameba/AtoAA"
|
||||
expect_raises(Runner::InfiniteCorrectionLoopError, message) do
|
||||
Runner.new(rules, [source], formatter, default_severity, autocorrect: true).run
|
||||
end
|
||||
end
|
||||
|
||||
context "exception in rule" do
|
||||
it "raises an exception raised in fiber while running a rule" do
|
||||
rule = RaiseRule.new
|
||||
|
@ -180,5 +196,56 @@ module Ameba
|
|||
.run.success?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#run with rules autocorrecting each other" do
|
||||
context "with two conflicting rules" do
|
||||
context "if there is an offense in an inspected file" do
|
||||
it "aborts because of an infinite loop" do
|
||||
rules = [AtoB.new, BtoA.new]
|
||||
source = Source.new "class A; end", "source.cr"
|
||||
message = "Infinite loop in source.cr caused by Ameba/AtoB -> Ameba/BtoA"
|
||||
expect_raises(Runner::InfiniteCorrectionLoopError, message) do
|
||||
Runner.new(rules, [source], formatter, default_severity, autocorrect: true).run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "if there are multiple offenses in an inspected file" do
|
||||
it "aborts because of an infinite loop" do
|
||||
rules = [AtoB.new, BtoA.new]
|
||||
source = Source.new %(
|
||||
class A; end
|
||||
class A_A; end
|
||||
), "source.cr"
|
||||
message = "Infinite loop in source.cr caused by Ameba/AtoB -> Ameba/BtoA"
|
||||
expect_raises(Runner::InfiniteCorrectionLoopError, message) do
|
||||
Runner.new(rules, [source], formatter, default_severity, autocorrect: true).run
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with two pairs of conflicting rules" do
|
||||
it "aborts because of an infinite loop" do
|
||||
rules = [ClassToModule.new, ModuleToClass.new, AtoB.new, BtoA.new]
|
||||
source = Source.new "class A_A; end", "source.cr"
|
||||
message = "Infinite loop in source.cr caused by Ameba/ClassToModule, Ameba/AtoB -> Ameba/ModuleToClass, Ameba/BtoA"
|
||||
expect_raises(Runner::InfiniteCorrectionLoopError, message) do
|
||||
Runner.new(rules, [source], formatter, default_severity, autocorrect: true).run
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with three rule cycle" do
|
||||
it "aborts because of an infinite loop" do
|
||||
rules = [AtoB.new, BtoC.new, CtoA.new]
|
||||
source = Source.new "class A; end", "source.cr"
|
||||
message = "Infinite loop in source.cr caused by Ameba/AtoB -> Ameba/BtoC -> Ameba/CtoA"
|
||||
expect_raises(Runner::InfiniteCorrectionLoopError, message) do
|
||||
Runner.new(rules, [source], formatter, default_severity, autocorrect: true).run
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -95,6 +95,133 @@ module Ameba
|
|||
end
|
||||
end
|
||||
|
||||
class AtoAA < Rule::Base
|
||||
include AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
||||
return unless (name = node_source(node.name, source.lines))
|
||||
return unless name.includes?("A")
|
||||
|
||||
issue_for(node.name, message: "A to AA") do |corrector|
|
||||
corrector.replace(node.name, name.sub("A", "AA"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class AtoB < Rule::Base
|
||||
include AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
||||
return unless (name = node_source(node.name, source.lines))
|
||||
return unless name.includes?("A")
|
||||
|
||||
issue_for(node.name, message: "A to B") do |corrector|
|
||||
corrector.replace(node.name, name.tr("A", "B"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BtoA < Rule::Base
|
||||
include AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
||||
return unless (name = node_source(node.name, source.lines))
|
||||
return unless name.includes?("B")
|
||||
|
||||
issue_for(node.name, message: "B to A") do |corrector|
|
||||
corrector.replace(node.name, name.tr("B", "A"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BtoC < Rule::Base
|
||||
include AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
||||
return unless (name = node_source(node.name, source.lines))
|
||||
return unless name.includes?("B")
|
||||
|
||||
issue_for(node.name, message: "B to C") do |corrector|
|
||||
corrector.replace(node.name, name.tr("B", "C"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class CtoA < Rule::Base
|
||||
include AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef | Crystal::ModuleDef)
|
||||
return unless (name = node_source(node.name, source.lines))
|
||||
return unless name.includes?("C")
|
||||
|
||||
issue_for(node.name, message: "C to A") do |corrector|
|
||||
corrector.replace(node.name, name.tr("C", "A"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ClassToModule < Ameba::Rule::Base
|
||||
include Ameba::AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ClassDef)
|
||||
return unless (location = node.location)
|
||||
|
||||
end_location = Crystal::Location.new(
|
||||
location.filename,
|
||||
location.line_number,
|
||||
location.column_number + "class".size - 1
|
||||
)
|
||||
issue_for(location, end_location, message: "class to module") do |corrector|
|
||||
corrector.replace(location, end_location, "module")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ModuleToClass < Ameba::Rule::Base
|
||||
include Ameba::AST::Util
|
||||
|
||||
properties do
|
||||
description "This rule is only used to test infinite loop detection"
|
||||
end
|
||||
|
||||
def test(source, node : Crystal::ModuleDef)
|
||||
return unless (location = node.location)
|
||||
|
||||
end_location = Crystal::Location.new(
|
||||
location.filename,
|
||||
location.line_number,
|
||||
location.column_number + "module".size - 1
|
||||
)
|
||||
issue_for(location, end_location, message: "module to class") do |corrector|
|
||||
corrector.replace(location, end_location, "class")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DummyFormatter < Formatter::BaseFormatter
|
||||
property started_sources : Array(Source)?
|
||||
property finished_sources : Array(Source)?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue