test-prof 0.7.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +174 -107
  3. data/LICENSE.txt +1 -1
  4. data/README.md +9 -3
  5. data/lib/minitest/base_reporter.rb +18 -12
  6. data/lib/minitest/test_prof_plugin.rb +8 -8
  7. data/lib/test_prof/any_fixture.rb +3 -3
  8. data/lib/test_prof/before_all/adapters/active_record.rb +11 -0
  9. data/lib/test_prof/before_all/isolator.rb +18 -0
  10. data/lib/test_prof/before_all.rb +82 -2
  11. data/lib/test_prof/cops/rspec/aggregate_failures.rb +6 -6
  12. data/lib/test_prof/event_prof/custom_events/factory_create.rb +27 -45
  13. data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +8 -38
  14. data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +7 -25
  15. data/lib/test_prof/event_prof/instrumentations/active_support.rb +1 -1
  16. data/lib/test_prof/event_prof/minitest.rb +4 -4
  17. data/lib/test_prof/event_prof/monitor.rb +45 -8
  18. data/lib/test_prof/event_prof/rspec.rb +4 -11
  19. data/lib/test_prof/event_prof.rb +6 -6
  20. data/lib/test_prof/ext/factory_bot_strategy.rb +24 -0
  21. data/lib/test_prof/factory_bot.rb +1 -1
  22. data/lib/test_prof/factory_default.rb +1 -1
  23. data/lib/test_prof/factory_doctor/fabrication_patch.rb +12 -0
  24. data/lib/test_prof/factory_doctor/factory_bot_patch.rb +5 -1
  25. data/lib/test_prof/factory_doctor/minitest.rb +4 -4
  26. data/lib/test_prof/factory_doctor/rspec.rb +15 -12
  27. data/lib/test_prof/factory_doctor.rb +29 -7
  28. data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +1 -1
  29. data/lib/test_prof/factory_prof/factory_builders/factory_bot.rb +2 -17
  30. data/lib/test_prof/factory_prof/printers/flamegraph.rb +6 -2
  31. data/lib/test_prof/factory_prof/printers/simple.rb +8 -6
  32. data/lib/test_prof/factory_prof.rb +29 -15
  33. data/lib/test_prof/recipes/logging.rb +86 -21
  34. data/lib/test_prof/recipes/minitest/before_all.rb +3 -2
  35. data/lib/test_prof/recipes/minitest/sample.rb +5 -5
  36. data/lib/test_prof/recipes/rspec/any_fixture.rb +3 -1
  37. data/lib/test_prof/recipes/rspec/before_all.rb +12 -3
  38. data/lib/test_prof/recipes/rspec/factory_all_stub.rb +5 -1
  39. data/lib/test_prof/recipes/rspec/let_it_be.rb +27 -12
  40. data/lib/test_prof/rspec_dissect/rspec.rb +2 -6
  41. data/lib/test_prof/rspec_dissect.rb +13 -19
  42. data/lib/test_prof/rspec_stamp/parser.rb +1 -1
  43. data/lib/test_prof/rspec_stamp/rspec.rb +1 -1
  44. data/lib/test_prof/rspec_stamp.rb +14 -14
  45. data/lib/test_prof/ruby_prof/rspec.rb +2 -6
  46. data/lib/test_prof/ruby_prof.rb +32 -24
  47. data/lib/test_prof/stack_prof/rspec.rb +5 -6
  48. data/lib/test_prof/stack_prof.rb +23 -15
  49. data/lib/test_prof/tag_prof/printers/simple.rb +4 -4
  50. data/lib/test_prof/tag_prof/result.rb +3 -3
  51. data/lib/test_prof/tag_prof/rspec.rb +9 -14
  52. data/lib/test_prof/utils/html_builder.rb +1 -1
  53. data/lib/test_prof/utils/sized_ordered_set.rb +1 -1
  54. data/lib/test_prof/version.rb +1 -1
  55. data/lib/test_prof.rb +6 -12
  56. metadata +35 -14
@@ -3,6 +3,7 @@
3
3
  require "test_prof"
4
4
  require "test_prof/factory_bot"
5
5
  require "test_prof/factory_doctor/factory_bot_patch"
6
+ require "test_prof/factory_doctor/fabrication_patch"
6
7
 
7
8
  module TestProf
8
9
  # FactoryDoctor is a tool that helps you identify
@@ -18,7 +19,7 @@ module TestProf
18
19
  end
19
20
 
20
21
  def bad?
21
- count > 0 && queries_count.zero?
22
+ count > 0 && queries_count.zero? && time >= FactoryDoctor.config.threshold
22
23
  end
23
24
  end
24
25
 
@@ -38,26 +39,47 @@ module TestProf
38
39
  \ASAVEPOINT
39
40
  )}xi.freeze
40
41
 
42
+ class Configuration
43
+ attr_accessor :event, :threshold
44
+
45
+ def initialize
46
+ # event to track for DB interactions
47
+ @event = ENV.fetch("FDOC_EVENT", "sql.active_record")
48
+ # consider result good if time wasted less then threshold
49
+ @threshold = ENV.fetch("FDOC_THRESHOLD", "0.01").to_f
50
+ end
51
+ end
52
+
41
53
  class << self
42
54
  include TestProf::Logging
43
55
 
44
- attr_reader :event
45
56
  attr_reader :count, :time, :queries_count
46
57
 
58
+ def config
59
+ @config ||= Configuration.new
60
+ end
61
+
62
+ def configure
63
+ yield config
64
+ end
65
+
47
66
  # Patch factory lib, init counters
48
- def init(event = 'sql.active_record')
49
- @event = event
67
+ def init
50
68
  reset!
51
69
 
52
- log :info, "FactoryDoctor enabled"
70
+ log :info, "FactoryDoctor enabled (event: \"#{config.event}\", threshold: #{config.threshold})"
53
71
 
54
72
  # Monkey-patch FactoryBot / FactoryGirl
55
73
  TestProf::FactoryBot::FactoryRunner.prepend(FactoryBotPatch) if
56
74
  defined?(TestProf::FactoryBot)
57
75
 
76
+ # Monkey-patch Fabrication
77
+ ::Fabricate.singleton_class.prepend(FabricationPatch) if
78
+ defined?(::Fabricate)
79
+
58
80
  subscribe!
59
81
 
60
- @stamp = ENV['FDOC_STAMP']
82
+ @stamp = ENV["FDOC_STAMP"]
61
83
 
62
84
  RSpecStamp.config.tags = @stamp if stamp?
63
85
  end
@@ -122,7 +144,7 @@ module TestProf
122
144
  end
123
145
 
124
146
  def subscribe!
125
- ::ActiveSupport::Notifications.subscribe(event) do |_name, _start, _finish, _id, query|
147
+ ::ActiveSupport::Notifications.subscribe(config.event) do |_name, _start, _finish, _id, query|
126
148
  next if ignore? || !running? || within_factory?
127
149
  next if query[:sql] =~ IGNORED_QUERIES_PATTERN
128
150
  @queries_count += 1
@@ -10,7 +10,7 @@ module TestProf
10
10
  class Fabrication
11
11
  # Monkey-patch Fabrication
12
12
  def self.patch
13
- TestProf.require 'fabrication' do
13
+ TestProf.require "fabrication" do
14
14
  ::Fabricate.singleton_class.prepend(FabricationPatch)
15
15
  end
16
16
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "test_prof/factory_prof/factory_bot_patch"
4
4
  require "test_prof/factory_bot"
5
+ require "test_prof/ext/factory_bot_strategy"
5
6
 
6
7
  module TestProf
7
8
  module FactoryProf
@@ -9,23 +10,7 @@ module TestProf
9
10
  # implementation of #patch and #track methods
10
11
  # to provide unified interface for all factory-building gems
11
12
  class FactoryBot
12
- # FactoryBot 5.0 uses strategy classes for associations,
13
- # older versions and top-level invocations use Symbols
14
- using(Module.new do
15
- refine Symbol do
16
- def create?
17
- self == :create
18
- end
19
- end
20
-
21
- if defined?(::FactoryBot::Strategy::Create)
22
- refine Class do
23
- def create?
24
- self <= ::FactoryBot::Strategy::Create
25
- end
26
- end
27
- end
28
- end)
13
+ using TestProf::FactoryBotStrategy
29
14
 
30
15
  # Monkey-patch FactoryBot / FactoryGirl
31
16
  def self.patch
@@ -15,7 +15,7 @@ module TestProf::FactoryProf
15
15
  return log(:info, "No factories detected") if result.raw_stats == {}
16
16
  report_data = {
17
17
  total_stacks: result.stacks.size,
18
- total: result.total
18
+ total: result.total_count
19
19
  }
20
20
 
21
21
  report_data[:roots] = convert_stacks(result)
@@ -45,7 +45,11 @@ module TestProf::FactoryProf
45
45
  node = paths[path]
46
46
  node[:value] += 1
47
47
  else
48
- node = { name: sample, value: 1, total: result.raw_stats.fetch(sample)[:total] }
48
+ node = {
49
+ name: sample,
50
+ value: 1,
51
+ total: result.raw_stats.fetch(sample)[:total_count]
52
+ }
49
53
  paths[path] = node
50
54
 
51
55
  if parent.nil?
@@ -10,23 +10,25 @@ module TestProf::FactoryProf
10
10
  return log(:info, "No factories detected") if result.raw_stats == {}
11
11
  msgs = []
12
12
 
13
- total = result.stats.sum { |stat| stat[:total] }
14
- total_top_level = result.stats.sum { |stat| stat[:top_level] }
13
+ total_count = result.stats.sum { |stat| stat[:total_count] }
14
+ total_top_level_count = result.stats.sum { |stat| stat[:top_level_count] }
15
+ total_time = result.stats.sum { |stat| stat[:top_level_time] }
15
16
  total_uniq_factories = result.stats.map { |stat| stat[:name] }.uniq.count
16
17
 
17
18
  msgs <<
18
19
  <<~MSG
19
20
  Factories usage
20
21
 
21
- Total: #{total}
22
- Total top-level: #{total_top_level}
22
+ Total: #{total_count}
23
+ Total top-level: #{total_top_level_count}
24
+ Total time: #{format("%.4f", total_time)}s
23
25
  Total uniq factories: #{total_uniq_factories}
24
26
 
25
- total top-level name
27
+ total top-level total time top-level time name
26
28
  MSG
27
29
 
28
30
  result.stats.each do |stat|
29
- msgs << format("%6d %11d %30s", stat[:total], stat[:top_level], stat[:name])
31
+ msgs << format("%8d %11d %11.4fs %15.4fs %30s", stat[:total_count], stat[:top_level_count], stat[:total_time], stat[:top_level_time], stat[:name])
30
32
  end
31
33
 
32
34
  log :info, msgs.join("\n")
@@ -17,7 +17,7 @@ module TestProf
17
17
  attr_accessor :mode
18
18
 
19
19
  def initialize
20
- @mode = ENV['FPROF'] == 'flamegraph' ? :flamegraph : :simple
20
+ @mode = ENV["FPROF"] == "flamegraph" ? :flamegraph : :simple
21
21
  end
22
22
 
23
23
  # Whether we want to generate flamegraphs
@@ -36,23 +36,24 @@ module TestProf
36
36
 
37
37
  # Returns sorted stats
38
38
  def stats
39
- return @stats if instance_variable_defined?(:@stats)
39
+ @stats ||= @raw_stats.values
40
+ .sort_by { |el| -el[:total_count] }
41
+ end
40
42
 
41
- @stats = @raw_stats.values
42
- .sort_by { |el| -el[:total] }
43
+ def total_count
44
+ @total_count ||= @raw_stats.values.sum { |v| v[:total_count] }
43
45
  end
44
46
 
45
- def total
46
- return @total if instance_variable_defined?(:@total)
47
- @total = @raw_stats.values.sum { |v| v[:total] }
47
+ def total_time
48
+ @total_time ||= @raw_stats.values.sum { |v| v[:total_time] }
48
49
  end
49
50
 
50
51
  private
51
52
 
52
53
  def sorted_stats(key)
53
54
  @raw_stats.values
54
- .map { |el| [el[:name], el[key]] }
55
- .sort_by { |el| -el[1] }
55
+ .map { |el| [el[:name], el[key]] }
56
+ .sort_by { |el| -el[1] }
56
57
  end
57
58
  end
58
59
 
@@ -103,13 +104,18 @@ module TestProf
103
104
 
104
105
  def track(factory)
105
106
  return yield unless running?
107
+ @depth += 1
108
+ @current_stack << factory if config.flamegraph?
109
+ @stats[factory][:total_count] += 1
110
+ @stats[factory][:top_level_count] += 1 if @depth == 1
111
+ t1 = TestProf.now
106
112
  begin
107
- @depth += 1
108
- @current_stack << factory if config.flamegraph?
109
- @stats[factory][:total] += 1
110
- @stats[factory][:top_level] += 1 if @depth == 1
111
113
  yield
112
114
  ensure
115
+ t2 = TestProf.now
116
+ elapsed = t2 - t1
117
+ @stats[factory][:total_time] += elapsed
118
+ @stats[factory][:top_level_time] += elapsed if @depth == 1
113
119
  @depth -= 1
114
120
  flush_stack if @depth.zero?
115
121
  end
@@ -120,7 +126,15 @@ module TestProf
120
126
  def reset!
121
127
  @stacks = [] if config.flamegraph?
122
128
  @depth = 0
123
- @stats = Hash.new { |h, k| h[k] = { name: k, total: 0, top_level: 0 } }
129
+ @stats = Hash.new do |h, k|
130
+ h[k] = {
131
+ name: k,
132
+ total_count: 0,
133
+ top_level_count: 0,
134
+ total_time: 0.0,
135
+ top_level_time: 0.0
136
+ }
137
+ end
124
138
  flush_stack
125
139
  end
126
140
 
@@ -137,6 +151,6 @@ module TestProf
137
151
  end
138
152
  end
139
153
 
140
- TestProf.activate('FPROF') do
154
+ TestProf.activate("FPROF") do
141
155
  TestProf::FactoryProf.run
142
156
  end
@@ -2,44 +2,109 @@
2
2
 
3
3
  require "test_prof"
4
4
 
5
+ module TestProf
6
+ module Rails
7
+ # Add `with_logging` and `with_ar_logging helpers`
8
+ module LoggingHelpers
9
+ class << self
10
+ attr_writer :logger
11
+
12
+ def logger
13
+ return @logger if instance_variable_defined?(:@logger)
14
+
15
+ @logger = Logger.new(STDOUT)
16
+ end
17
+
18
+ def ar_loggables
19
+ return @ar_loggables if instance_variable_defined?(:@ar_loggables)
20
+
21
+ @ar_loggables = [
22
+ ::ActiveRecord::Base,
23
+ ::ActiveSupport::LogSubscriber
24
+ ]
25
+ end
26
+
27
+ # rubocop:disable Metrics/CyclomaticComplexity
28
+ # rubocop:disable Metrics/PerceivedComplexity
29
+ def all_loggables
30
+ return @all_loggables if instance_variable_defined?(:@all_loggables)
31
+
32
+ @all_loggables = [
33
+ ::ActiveSupport::LogSubscriber,
34
+ ::Rails,
35
+ defined?(::ActiveRecord::Base) && ::ActiveRecord::Base,
36
+ defined?(::ActiveJob::Base) && ::ActiveJob::Base,
37
+ defined?(::ActionView::Base) && ::ActionView::Base,
38
+ defined?(::ActionMailer::Base) && ::ActionMailer::Base,
39
+ defined?(::ActionCable::Server::Base.config) && ::ActionCable::Server::Base.config,
40
+ defined?(::ActiveStorage) && ::ActiveStorage
41
+ ].compact
42
+ end
43
+ # rubocop:enable Metrics/CyclomaticComplexity
44
+ # rubocop:enable Metrics/PerceivedComplexity
45
+
46
+ def swap_logger(loggables)
47
+ loggables.map do |loggable|
48
+ was_logger = loggable.logger
49
+ loggable.logger = logger
50
+ was_logger
51
+ end
52
+ end
53
+
54
+ def restore_logger(was_loggers, loggables)
55
+ loggables.each_with_index do |loggable, i|
56
+ loggable.logger = was_loggers[i]
57
+ end
58
+ end
59
+ end
60
+
61
+ # Enable verbose Rails logging within a block
62
+ def with_logging
63
+ *loggers = LoggingHelpers.swap_logger(LoggingHelpers.all_loggables)
64
+ yield
65
+ ensure
66
+ LoggingHelpers.restore_logger(loggers, LoggingHelpers.all_loggables)
67
+ end
68
+
69
+ def with_ar_logging
70
+ *loggers = LoggingHelpers.swap_logger(LoggingHelpers.ar_loggables)
71
+ yield
72
+ ensure
73
+ LoggingHelpers.restore_logger(loggers, LoggingHelpers.ar_loggables)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
5
79
  if TestProf.rspec?
6
- RSpec.shared_context "logging:verbose", log: true do
80
+ RSpec.shared_context "logging:verbose" do
7
81
  around(:each) do |ex|
8
- *loggers = ActiveSupport::LogSubscriber.logger,
9
- Rails.logger,
10
- ActiveRecord::Base.logger
11
- ActiveSupport::LogSubscriber.logger =
12
- Rails.logger =
13
- ActiveRecord::Base.logger = Logger.new(STDOUT)
14
- ex.run
15
- ActiveSupport::LogSubscriber.logger,
16
- Rails.logger,
17
- ActiveRecord::Base.logger = *loggers
82
+ with_logging(&ex)
18
83
  end
19
84
  end
20
85
 
21
- RSpec.shared_context "logging:active_record", log: :ar do
86
+ RSpec.shared_context "logging:active_record" do
22
87
  around(:each) do |ex|
23
- *loggers = ActiveRecord::Base.logger,
24
- ActiveSupport::LogSubscriber.logger
25
- ActiveSupport::LogSubscriber.logger =
26
- ActiveRecord::Base.logger = Logger.new(STDOUT)
27
- ex.run
28
- ActiveSupport::LogSubscriber.logger,
29
- ActiveRecord::Base.logger = *loggers
88
+ with_ar_logging(&ex)
30
89
  end
31
90
  end
91
+
92
+ RSpec.configure do |config|
93
+ config.include TestProf::Rails::LoggingHelpers
94
+ config.include_context "logging:active_record", log: :ar
95
+ config.include_context "logging:verbose", log: true
96
+ end
32
97
  end
33
98
 
34
99
  TestProf.activate("LOG", "all") do
35
100
  TestProf.log :info, "Rails verbose logging enabled"
36
101
  ActiveSupport::LogSubscriber.logger =
37
102
  Rails.logger =
38
- ActiveRecord::Base.logger = Logger.new(STDOUT)
103
+ ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
39
104
  end
40
105
 
41
106
  TestProf.activate("LOG", "ar") do
42
107
  TestProf.log :info, "Active Record verbose logging enabled"
43
108
  ActiveSupport::LogSubscriber.logger =
44
- ActiveRecord::Base.logger = Logger.new(STDOUT)
109
+ ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
45
110
  end
@@ -20,8 +20,9 @@ module TestProf
20
20
  return if active?
21
21
  @active = true
22
22
  @examples_left = test_class.runnable_methods.size
23
- BeforeAll.begin_transaction
24
- capture!
23
+ BeforeAll.begin_transaction do
24
+ capture!
25
+ end
25
26
  end
26
27
 
27
28
  def try_deactivate!
@@ -14,7 +14,7 @@ module TestProf
14
14
  def suites
15
15
  # Make sure that sample contains only _real_ suites
16
16
  Minitest::Runnable.runnables
17
- .reject { |suite| CORE_RUNNABLES.include?(suite) }
17
+ .reject { |suite| CORE_RUNNABLES.include?(suite) }
18
18
  end
19
19
 
20
20
  def sample_groups(sample_size)
@@ -39,10 +39,10 @@ module TestProf
39
39
 
40
40
  # Overrides Minitest.run
41
41
  def run(*)
42
- if ENV['SAMPLE']
43
- MinitestSample.sample_examples(ENV['SAMPLE'].to_i)
44
- elsif ENV['SAMPLE_GROUPS']
45
- MinitestSample.sample_groups(ENV['SAMPLE_GROUPS'].to_i)
42
+ if ENV["SAMPLE"]
43
+ MinitestSample.sample_examples(ENV["SAMPLE"].to_i)
44
+ elsif ENV["SAMPLE_GROUPS"]
45
+ MinitestSample.sample_groups(ENV["SAMPLE_GROUPS"].to_i)
46
46
  end
47
47
  super
48
48
  end
@@ -3,7 +3,7 @@
3
3
  require "test_prof/any_fixture"
4
4
  require "test_prof/recipes/rspec/before_all"
5
5
 
6
- RSpec.shared_context "any_fixture:clean", with_clean_fixture: true do
6
+ RSpec.shared_context "any_fixture:clean" do
7
7
  extend TestProf::BeforeAll::RSpec
8
8
 
9
9
  before_all do
@@ -12,6 +12,8 @@ RSpec.shared_context "any_fixture:clean", with_clean_fixture: true do
12
12
  end
13
13
 
14
14
  RSpec.configure do |config|
15
+ config.include_context "any_fixture:clean", with_clean_fixture: true
16
+
15
17
  config.after(:suite) do
16
18
  TestProf::AnyFixture.report_stats if TestProf::AnyFixture.reporting_enabled?
17
19
  TestProf::AnyFixture.reset
@@ -9,13 +9,14 @@ module TestProf
9
9
  def before_all(&block)
10
10
  raise ArgumentError, "Block is required!" unless block_given?
11
11
 
12
- return before(:all, &block) if within_before_all?
12
+ return within_before_all(&block) if within_before_all?
13
13
 
14
14
  @__before_all_activated__ = true
15
15
 
16
16
  before(:all) do
17
- BeforeAll.begin_transaction
18
- instance_eval(&block)
17
+ BeforeAll.begin_transaction do
18
+ instance_eval(&block)
19
+ end
19
20
  end
20
21
 
21
22
  after(:all) do
@@ -23,6 +24,14 @@ module TestProf
23
24
  end
24
25
  end
25
26
 
27
+ def within_before_all(&block)
28
+ before(:all) do
29
+ BeforeAll.within_transaction do
30
+ instance_eval(&block)
31
+ end
32
+ end
33
+ end
34
+
26
35
  def within_before_all?
27
36
  instance_variable_defined?(:@__before_all_activated__)
28
37
  end
@@ -4,7 +4,11 @@ require "test_prof/factory_all_stub"
4
4
 
5
5
  TestProf::FactoryAllStub.init
6
6
 
7
- RSpec.shared_context "factory:stub", factory: :stub do
7
+ RSpec.shared_context "factory:stub" do
8
8
  prepend_before(:all) { TestProf::FactoryAllStub.enable! }
9
9
  append_after(:all) { TestProf::FactoryAllStub.disable! }
10
10
  end
11
+
12
+ RSpec.configure do |config|
13
+ config.include_context "factory:stub", factory: :stub
14
+ end
@@ -7,18 +7,32 @@ module TestProf
7
7
  # Just like `let`, but persist the result for the whole group.
8
8
  # NOTE: Experimental and magical, for more control use `before_all`.
9
9
  module LetItBe
10
+ class Configuration
11
+ # Define an alias for `let_it_be` with the predefined options:
12
+ #
13
+ # TestProf::LetItBe.configure do |config|
14
+ # config.alias_to :let_it_be_reloaded, reload: true
15
+ # end
16
+ def alias_to(name, **default_args)
17
+ LetItBe.define_let_it_be_alias(name, **default_args)
18
+ end
19
+ end
20
+
10
21
  class << self
22
+ def config
23
+ @config ||= Configuration.new
24
+ end
25
+
26
+ def configure
27
+ yield config
28
+ end
29
+
11
30
  def module_for(group)
12
31
  modules[group] ||= begin
13
32
  Module.new.tap { |mod| group.prepend(mod) }
14
33
  end
15
34
  end
16
35
 
17
- # Only works with RSpec 3.2.0
18
- def supported?
19
- TestProf::Utils.verify_gem_version('rspec-core', at_least: '3.2.0')
20
- end
21
-
22
36
  private
23
37
 
24
38
  def modules
@@ -28,20 +42,21 @@ module TestProf
28
42
  # Use uniq prefix for instance variables to avoid collisions
29
43
  # We want to use the power of Ruby's unicode support)
30
44
  # And we love cats!)
31
- PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__" : "@😸"
45
+ PREFIX = RUBY_ENGINE == "jruby" ? "@__jruby_is_not_cat_friendly__" : "@😸"
32
46
 
33
- def let_it_be(identifier, **options, &block)
34
- unless LetItBe.supported?
35
- TestProf.log :warn, "let_it_be requires RSpec >= 3.2.0. Fallback to let!"
36
- return let!(identifier, &block)
47
+ def self.define_let_it_be_alias(name, **default_args)
48
+ define_method(name) do |identifier, **options, &blk|
49
+ let_it_be(identifier, default_args.merge(options), &blk)
37
50
  end
51
+ end
38
52
 
53
+ def let_it_be(identifier, **options, &block)
39
54
  initializer = proc do
40
55
  instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
41
56
  end
42
57
 
43
58
  if within_before_all?
44
- before(:all, &initializer)
59
+ within_before_all(&initializer)
45
60
  else
46
61
  before_all(&initializer)
47
62
  end
@@ -72,7 +87,7 @@ module TestProf
72
87
  LetItBe.module_for(self).module_eval do
73
88
  define_method(identifier) do
74
89
  # Trying to detect the context (couldn't find other way so far)
75
- if @__inspect_output =~ /\(:context\)/
90
+ if /\(:context\)/.match?(@__inspect_output)
76
91
  instance_variable_get(:"#{PREFIX}#{identifier}")
77
92
  else
78
93
  # Fallback to let definition
@@ -10,8 +10,7 @@ module TestProf
10
10
 
11
11
  NOTIFICATIONS = %i[
12
12
  example_group_finished
13
- example_passed
14
- example_failed
13
+ example_finished
15
14
  ].freeze
16
15
 
17
16
  def initialize
@@ -35,9 +34,6 @@ module TestProf
35
34
  @examples_time += notification.example.execution_result.run_time
36
35
  end
37
36
 
38
- alias example_passed example_finished
39
- alias example_failed example_finished
40
-
41
37
  def example_group_finished(notification)
42
38
  return unless notification.group.top_level?
43
39
 
@@ -127,7 +123,7 @@ module TestProf
127
123
  end
128
124
 
129
125
  # Register RSpecDissect listener
130
- TestProf.activate('RD_PROF') do
126
+ TestProf.activate("RD_PROF") do
131
127
  RSpec.configure do |config|
132
128
  listener = nil
133
129
 
@@ -21,10 +21,10 @@ module TestProf
21
21
  Thread.current[:_rspec_dissect_let_depth] += 1
22
22
  begin
23
23
  res = if Thread.current[:_rspec_dissect_let_depth] == 1
24
- RSpecDissect.track(:let, id) { super }
25
- else
26
- super
27
- end
24
+ RSpecDissect.track(:let, id) { super }
25
+ else
26
+ super
27
+ end
28
28
  ensure
29
29
  Thread.current[:_rspec_dissect_let_depth] -= 1
30
30
  end
@@ -45,14 +45,14 @@ module TestProf
45
45
 
46
46
  def initialize
47
47
  @let_stats_enabled = true
48
- @let_top_count = (ENV['RD_PROF_LET_TOP'] || 3).to_i
49
- @top_count = (ENV['RD_PROF_TOP'] || 5).to_i
50
- @stamp = ENV['RD_PROF_STAMP']
51
- @mode = ENV['RD_PROF'] == '1' ? 'all' : ENV['RD_PROF']
48
+ @let_top_count = (ENV["RD_PROF_LET_TOP"] || 3).to_i
49
+ @top_count = (ENV["RD_PROF_TOP"] || 5).to_i
50
+ @stamp = ENV["RD_PROF_STAMP"]
51
+ @mode = ENV["RD_PROF"] == "1" ? "all" : ENV["RD_PROF"]
52
52
 
53
53
  unless MODES.include?(mode)
54
54
  raise "Unknown RSpecDissect mode: #{mode};" \
55
- "available modes: #{MODES.join(', ')}"
55
+ "available modes: #{MODES.join(", ")}"
56
56
  end
57
57
 
58
58
  RSpecStamp.config.tags = @stamp if stamp?
@@ -87,10 +87,8 @@ module TestProf
87
87
  def init
88
88
  RSpec::Core::Example.prepend(ExampleInstrumentation)
89
89
 
90
- if memoization_available?
91
- RSpec::Core::MemoizedHelpers::ThreadsafeMemoized.prepend(MemoizedInstrumentation)
92
- RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized.prepend(MemoizedInstrumentation)
93
- end
90
+ RSpec::Core::MemoizedHelpers::ThreadsafeMemoized.prepend(MemoizedInstrumentation)
91
+ RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized.prepend(MemoizedInstrumentation)
94
92
 
95
93
  @data = {}
96
94
 
@@ -100,10 +98,6 @@ module TestProf
100
98
 
101
99
  reset!
102
100
 
103
- if config.let? && !memoization_available?
104
- log :warn, "RSpecDissect: `let` profiling is not supported (requires RSpec >= 3.3.0)\n"
105
- end
106
-
107
101
  log :info, "RSpecDissect enabled"
108
102
  end
109
103
 
@@ -120,7 +114,7 @@ module TestProf
120
114
 
121
115
  def reset!
122
116
  METRICS.each do |type|
123
- @data[type.to_s] = { time: 0.0, meta: [] }
117
+ @data[type.to_s] = {time: 0.0, meta: []}
124
118
  end
125
119
  end
126
120
 
@@ -148,6 +142,6 @@ require "test_prof/rspec_dissect/collectors/let"
148
142
  require "test_prof/rspec_dissect/collectors/before"
149
143
  require "test_prof/rspec_dissect/rspec" if TestProf.rspec?
150
144
 
151
- TestProf.activate('RD_PROF') do
145
+ TestProf.activate("RD_PROF") do
152
146
  TestProf::RSpecDissect.init
153
147
  end