1
0
Fork 0
mirror of https://github.com/thoughtbot/factory_bot.git synced 2022-11-09 11:43:51 -05:00
thoughtbot--factory_bot/lib/factory_bot/linter.rb
Daniel Colson 40788b0c12 Refactor Linter to simplify adding verbose option
This refactoring work should make adding the verbose linting option
(started in PR #1233) fairly simple.

I moved the linting option defaults into keyword argument defaults for
Linter#initialize. With keyword arguments we will now get an error if we
pass an option the Linter doesn't understand (we were doing exactly this
in one of our tests before 6e511597). Adding the verbose option will now
be as simple as adding another keyword argument, then adding backtraces
to the error messages when the option is set to true.
2018-11-27 10:47:24 -05:00

98 lines
2.3 KiB
Ruby

module FactoryBot
class Linter
def initialize(factories, strategy: :create, traits: false)
@factories_to_lint = factories
@factory_strategy = strategy
@traits = traits
@invalid_factories = calculate_invalid_factories
end
def lint!
if invalid_factories.any?
raise InvalidFactoryError, error_message
end
end
private
attr_reader :factories_to_lint, :invalid_factories, :factory_strategy
def calculate_invalid_factories
factories_to_lint.reduce(Hash.new([])) do |result, factory|
errors = lint(factory)
result[factory] |= errors unless errors.empty?
result
end
end
class FactoryError
def initialize(wrapped_error, factory)
@wrapped_error = wrapped_error
@factory = factory
end
def message
message = @wrapped_error.message
"* #{location} - #{message} (#{@wrapped_error.class.name})"
end
def location
@factory.name
end
end
class FactoryTraitError < FactoryError
def initialize(wrapped_error, factory, trait_name)
super(wrapped_error, factory)
@trait_name = trait_name
end
def location
"#{@factory.name}+#{@trait_name}"
end
end
def lint(factory)
if @traits
lint_factory(factory) + lint_traits(factory)
else
lint_factory(factory)
end
end
def lint_factory(factory)
result = []
begin
FactoryBot.public_send(factory_strategy, factory.name)
rescue StandardError => error
result |= [FactoryError.new(error, factory)]
end
result
end
def lint_traits(factory)
result = []
factory.definition.defined_traits.map(&:name).each do |trait_name|
begin
FactoryBot.public_send(factory_strategy, factory.name, trait_name)
rescue StandardError => error
result |=
[FactoryTraitError.new(error, factory, trait_name)]
end
end
result
end
def error_message
lines = invalid_factories.map do |_factory, exceptions|
exceptions.map(&:message)
end.flatten
<<~ERROR_MESSAGE.strip
The following factories are invalid:
#{lines.join("\n")}
ERROR_MESSAGE
end
end
end