1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
# frozen_string_literal: true
require "test_prof/ext/float_duration"
module TestProf
module FactoryDoctor
class RSpecListener # :nodoc:
include Logging
using FloatDuration
SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
NOTIFICATIONS = %i[
example_started
example_finished
].freeze
def initialize
@count = 0
@time = 0.0
@example_groups = Hash.new { |h, k| h[k] = [] }
end
def example_started(_notification)
FactoryDoctor.start
end
def example_finished(notification)
FactoryDoctor.stop
return if notification.example.pending?
result = FactoryDoctor.result
return unless result.bad?
group = notification.example.example_group.parent_groups.last
notification.example.metadata.merge!(
factories: result.count,
time: result.time
)
@example_groups[group] << notification.example
@count += 1
@time += result.time
end
def print
return log(:info, SUCCESS_MESSAGE) if @example_groups.empty?
msgs = []
msgs <<
<<~MSG
FactoryDoctor report
Total (potentially) bad examples: #{@count}
Total wasted time: #{@time.duration}
MSG
@example_groups.each do |group, examples|
group_time = examples.sum { |ex| ex.metadata[:time] }
group_count = examples.sum { |ex| ex.metadata[:factories] }
msgs << "#{group.description} (#{group.metadata[:location]}) " \
"(#{pluralize_records(group_count)} created, " \
"#{group_time.duration})\n"
examples.each do |ex|
msgs << " #{ex.description} (#{ex.metadata[:location]}) " \
"– #{pluralize_records(ex.metadata[:factories])} created, "\
"#{ex.metadata[:time].duration}\n"
end
msgs << "\n"
end
log :info, msgs.join
stamp! if FactoryDoctor.stamp?
end
def stamp!
stamper = RSpecStamp::Stamper.new
examples = Hash.new { |h, k| h[k] = [] }
@example_groups.each_value do |bad_examples|
bad_examples.each do |example|
file, line = example.metadata[:location].split(":")
examples[file] << line.to_i
end
end
examples.each do |file, lines|
stamper.stamp_file(file, lines.uniq)
end
msgs = []
msgs <<
<<~MSG
RSpec Stamp results
Total patches: #{stamper.total}
Total files: #{examples.keys.size}
Failed patches: #{stamper.failed}
Ignored files: #{stamper.ignored}
MSG
log :info, msgs.join
end
private
def pluralize_records(count)
return "1 record" if count == 1
"#{count} records"
end
end
end
end
# Register FactoryDoctor listener
TestProf.activate("FDOC") do
TestProf::FactoryDoctor.init
RSpec.configure do |config|
listener = nil
config.before(:suite) do
listener = TestProf::FactoryDoctor::RSpecListener.new
config.reporter.register_listener(
listener, *TestProf::FactoryDoctor::RSpecListener::NOTIFICATIONS
)
end
config.after(:suite) { listener&.print }
end
RSpec.shared_context "factory_doctor:ignore" do
around(:each) { |ex| TestProf::FactoryDoctor.ignore(&ex) }
end
RSpec.configure do |config|
config.include_context "factory_doctor:ignore", fd_ignore: true
end
end
|