mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
40788b0c12
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.
98 lines
2.3 KiB
Ruby
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
|