shard-ameba/spec/spec_helper.cr

303 lines
7 KiB
Crystal
Raw Normal View History

2017-10-26 16:46:58 +00:00
require "spec"
require "../src/ameba"
require "../src/ameba/spec/support"
2017-10-30 20:00:01 +00:00
2017-11-01 20:05:41 +00:00
module Ameba
2018-12-08 20:52:32 +00:00
# Dummy Rule which does nothing.
2021-01-18 15:45:35 +00:00
class DummyRule < Rule::Base
2017-11-22 06:44:29 +00:00
properties do
description : String = "Dummy rule that does nothing."
2022-11-22 18:53:27 +00:00
dummy true
2017-11-22 06:44:29 +00:00
end
2017-11-01 20:05:41 +00:00
def test(source)
end
2017-10-30 20:00:01 +00:00
end
2017-11-30 21:50:07 +00:00
2021-01-18 15:45:35 +00:00
class NamedRule < Rule::Base
properties do
2020-06-15 11:19:23 +00:00
description "A rule with a custom name."
end
def self.name
"BreakingRule"
end
end
2022-11-25 04:02:37 +00:00
# Rule extended description
2021-01-18 15:45:35 +00:00
class ErrorRule < Rule::Base
properties do
2020-06-15 11:19:23 +00:00
description "Always adds an error at 1:1"
end
2017-11-30 21:50:07 +00:00
def test(source)
2018-06-10 21:15:12 +00:00
issue_for({1, 1}, "This rule always adds an error")
2017-11-30 21:50:07 +00:00
end
end
2017-11-01 20:05:41 +00:00
2021-01-18 15:45:35 +00:00
class ScopeRule < Rule::Base
2020-06-15 11:19:23 +00:00
@[YAML::Field(ignore: true)]
getter scopes = [] of AST::Scope
2020-06-15 11:19:23 +00:00
properties do
description "Internal rule to test scopes"
end
2023-06-07 23:58:58 +00:00
def test(source, node : Crystal::VisibilityModifier, scope : AST::Scope)
end
def test(source, node : Crystal::ASTNode, scope : AST::Scope)
@scopes << scope
end
end
2021-01-18 15:45:35 +00:00
class FlowExpressionRule < Rule::Base
2020-06-15 11:19:23 +00:00
@[YAML::Field(ignore: true)]
getter expressions = [] of AST::FlowExpression
2020-06-15 11:19:23 +00:00
properties do
description "Internal rule to test flow expressions"
end
def test(source, node, flow_expression : AST::FlowExpression)
@expressions << flow_expression
end
end
2021-01-18 15:45:35 +00:00
class RedundantControlExpressionRule < Rule::Base
2020-06-15 11:19:23 +00:00
@[YAML::Field(ignore: true)]
2020-03-24 16:01:23 +00:00
getter nodes = [] of Crystal::ASTNode
2020-06-15 11:19:23 +00:00
properties do
description "Internal rule to test redundant control expressions"
2020-03-24 16:01:23 +00:00
end
def test(source, node, visitor : AST::RedundantControlExpressionVisitor)
nodes << node
end
end
# A rule that always raises an error
2021-01-18 15:45:35 +00:00
class RaiseRule < Rule::Base
2022-11-22 18:51:48 +00:00
property? should_raise = false
2020-06-15 11:19:23 +00:00
properties do
description "Internal rule that always raises"
end
def test(source)
2022-11-22 18:51:48 +00:00
should_raise? && raise "something went wrong"
end
end
class PerfRule < Rule::Performance::Base
properties do
description : String = "Sample performance rule"
end
def test(source)
issue_for({1, 1}, "Poor performance")
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)
2021-11-16 21:30:33 +00:00
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)
2021-11-16 21:30:33 +00:00
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)
2021-11-16 21:30:33 +00:00
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)
2021-11-16 21:30:33 +00:00
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)
2021-11-16 21:30:33 +00:00
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)
2021-11-16 21:30:33 +00:00
return unless location = node.location
2022-11-14 00:24:29 +00:00
end_location = location.adjust(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)
2021-11-16 21:30:33 +00:00
return unless location = node.location
2022-11-14 00:24:29 +00:00
end_location = location.adjust(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)?
property started_source : Source?
property finished_source : Source?
def started(sources)
@started_sources = sources
end
def source_finished(source : Source)
@started_source = source
end
def source_started(source : Source)
@finished_source = source
end
def finished(sources)
@finished_sources = sources
end
end
class TestNodeVisitor < Crystal::Visitor
2022-11-23 02:23:42 +00:00
NODES = {
Crystal::NilLiteral,
Crystal::Var,
Crystal::Assign,
Crystal::OpAssign,
Crystal::MultiAssign,
Crystal::Block,
Crystal::Macro,
Crystal::Def,
Crystal::If,
Crystal::While,
Crystal::MacroLiteral,
Crystal::Expressions,
2020-03-24 16:01:23 +00:00
Crystal::ControlExpression,
2022-11-23 02:23:42 +00:00
}
def initialize(node)
node.accept self
end
def visit(node : Crystal::ASTNode)
true
end
{% for node in NODES %}
2022-11-14 00:24:29 +00:00
{{ getter_name = node.stringify.split("::").last.underscore + "_nodes" }}
2022-11-14 00:24:29 +00:00
getter {{ getter_name.id }} = [] of {{ node }}
2022-11-14 00:24:29 +00:00
def visit(node : {{ node }})
{{ getter_name.id }} << node
true
end
{% end %}
end
2017-11-01 20:05:41 +00:00
end
2023-11-05 05:09:06 +00:00
def with_presenter(klass, &)
io = IO::Memory.new
presenter = klass.new(io)
yield presenter, io
end
def as_node(source)
Crystal::Parser.new(source).parse
end
def as_nodes(source)
Ameba::TestNodeVisitor.new(as_node source)
end
2022-12-19 23:34:11 +00:00
def trailing_whitespace
' '
end