test-prof 0.6.0 → 0.7.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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/README.md +1 -1
  4. data/lib/minitest/event_prof_formatter.rb +3 -5
  5. data/lib/test_prof/any_fixture.rb +2 -4
  6. data/lib/test_prof/before_all.rb +1 -1
  7. data/lib/test_prof/cops/rspec/aggregate_failures.rb +2 -2
  8. data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -4
  9. data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +1 -5
  10. data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +1 -5
  11. data/lib/test_prof/event_prof/monitor.rb +1 -5
  12. data/lib/test_prof/event_prof/rspec.rb +5 -7
  13. data/lib/test_prof/factory_doctor/minitest.rb +2 -4
  14. data/lib/test_prof/factory_doctor/rspec.rb +4 -6
  15. data/lib/test_prof/factory_prof/printers/flamegraph.rb +2 -2
  16. data/lib/test_prof/factory_prof/printers/simple.rb +1 -4
  17. data/lib/test_prof/recipes/active_record_one_love.rb +2 -0
  18. data/lib/test_prof/recipes/logging.rb +10 -4
  19. data/lib/test_prof/recipes/rspec/let_it_be.rb +2 -2
  20. data/lib/test_prof/rspec_dissect/collectors/base.rb +2 -4
  21. data/lib/test_prof/rspec_dissect/rspec.rb +3 -5
  22. data/lib/test_prof/rspec_stamp/parser.rb +2 -2
  23. data/lib/test_prof/rspec_stamp/rspec.rb +2 -5
  24. data/lib/test_prof/ruby_prof.rb +61 -28
  25. data/lib/test_prof/ruby_prof/rspec_exclusions.rb +93 -0
  26. data/lib/test_prof/stack_prof.rb +3 -6
  27. data/lib/test_prof/tag_prof/printers/html.rb +2 -2
  28. data/lib/test_prof/tag_prof/printers/simple.rb +1 -3
  29. data/lib/test_prof/tag_prof/rspec.rb +3 -3
  30. data/lib/test_prof/version.rb +1 -1
  31. metadata +6 -6
  32. data/lib/test_prof/ext/string_strip_heredoc.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03ab3753dd924402ef2d09973165d82d17d2e72c26ad317e6513111ff1b93166
4
- data.tar.gz: 93cbd1952a5054e0c2f76058e227a6e03c0bb6b050f20a74d54fd57b85401e69
3
+ metadata.gz: e8baffb743630e819928190645aa63d73436f2dc54fc2c56ab1ad5df8141ed3c
4
+ data.tar.gz: 7738b154073f150e23df40193f350e93e2fb047758023021acef237e08988da3
5
5
  SHA512:
6
- metadata.gz: 6f6a2ed0ba54bf9c4e0633b842fa5c961ab832f4a45013e44ae68804c1714b6708be22505c7b6de38a6e90a2661f64c684efefbb07d1569ef22cbdf17d5cef57
7
- data.tar.gz: 79fa0b40361b533cde8f26c45ed66add0a70cad73f59c5ddcabe6f2997fb944293b36a33f557e4870667a7f023e84219216ef6d4e1ee9d54b316ac038cb281e3
6
+ metadata.gz: f2f75e27df1795a31f3e39312bfa6268502881f1fd6cb28376603f0486048376d12d5e0266edb2eb7e76f6a54723ae03c43a6c35167242fe2c361b12535cda93
7
+ data.tar.gz: 56b472304e1291e9f392a2c62c36bc40fc2ad575c0b976d46a8f2fd881bfbf2db3f0948014dd29b99cf63eccded2a63b0ddd834676221f354e872622a80dc883
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.7.0 (2018-08-12)
6
+
7
+ - **Ruby 2.3+ is required**. ([@palkan][])
8
+
9
+ Ruby 2.2 EOL was on 2018-03-31.
10
+
11
+ - Upgrade RubyProf integration to `ruby-prof >= 0.17`. ([@palkan][])
12
+
13
+ Use `exclude_common_methods!` instead of the deprecated `eliminate_methods!`.
14
+
15
+ Add RSpec specific exclusions.
16
+
17
+ Add ability to specify custom exclusions through `config.custom_exclusions`, e.g.:
18
+
19
+ ```ruby
20
+ TestProf::RubyProf.configure do |config|
21
+ config.custom_exclusions = { User => %i[save save!] }
22
+ end
23
+ ```
24
+
5
25
  ## 0.6.0 (2018-06-29)
6
26
 
7
27
  ### Features
data/README.md CHANGED
@@ -32,7 +32,7 @@ Of course, we have some [solutions](https://test-prof.evilmartians.io/#/?id=reci
32
32
 
33
33
  Supported Ruby versions:
34
34
 
35
- - Ruby (MRI) >= 2.2.0 (**NOTE:** the next release will require 2.3+)
35
+ - Ruby (MRI) >= 2.3.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0)
36
36
 
37
37
  - JRuby >= 9.1.0.0
38
38
 
@@ -2,14 +2,12 @@
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
4
  require "test_prof/ext/string_truncate"
5
- require "test_prof/ext/string_strip_heredoc"
6
5
 
7
6
  module Minitest
8
7
  module TestProf
9
8
  class EventProfFormatter # :nodoc:
10
9
  using ::TestProf::FloatDuration
11
10
  using ::TestProf::StringTruncate
12
- using ::TestProf::StringStripHeredoc
13
11
 
14
12
  def initialize(profilers)
15
13
  @profilers = profilers
@@ -29,7 +27,7 @@ module Minitest
29
27
 
30
28
  def total_results(profiler)
31
29
  @results <<
32
- <<-MSG.strip_heredoc
30
+ <<~MSG
33
31
  EventProf results for #{profiler.event}
34
32
 
35
33
  Total time: #{profiler.total_time.duration}
@@ -46,7 +44,7 @@ module Minitest
46
44
  location = group[:id][:location]
47
45
 
48
46
  @results <<
49
- <<-GROUP.strip_heredoc
47
+ <<~GROUP
50
48
  #{description.truncate} (#{location}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
51
49
  GROUP
52
50
  end
@@ -61,7 +59,7 @@ module Minitest
61
59
  location = example[:id][:location]
62
60
 
63
61
  @results <<
64
- <<-GROUP.strip_heredoc
62
+ <<~GROUP
65
63
  #{description.truncate} (#{location}) – #{example[:time].duration} (#{example[:count]})
66
64
  GROUP
67
65
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf
7
6
  # Make DB fixtures from blocks.
@@ -9,7 +8,6 @@ module TestProf
9
8
  INSERT_RXP = /^INSERT INTO ([\S]+)/
10
9
 
11
10
  using FloatDuration
12
- using StringStripHeredoc
13
11
 
14
12
  class Cache # :nodoc:
15
13
  attr_reader :store, :stats
@@ -85,7 +83,7 @@ module TestProf
85
83
  msgs = []
86
84
 
87
85
  msgs <<
88
- <<-MSG.strip_heredoc
86
+ <<~MSG
89
87
  AnyFixture usage stats:
90
88
  MSG
91
89
 
@@ -119,7 +117,7 @@ module TestProf
119
117
  end
120
118
 
121
119
  msgs <<
122
- <<-MSG.strip_heredoc
120
+ <<~MSG
123
121
 
124
122
  Total time spent: #{total_spent.duration}
125
123
  Total time saved: #{total_saved.duration}
@@ -5,7 +5,7 @@ module TestProf
5
5
  module BeforeAll
6
6
  class AdapterMissing < StandardError # :nodoc:
7
7
  MSG = "Please, provide an adapter for `before_all` " \
8
- "through `TestProf::BeforeAll.adapter = MyAdapter`".freeze
8
+ "through `TestProf::BeforeAll.adapter = MyAdapter`"
9
9
 
10
10
  def initialize
11
11
  super(MSG)
@@ -50,7 +50,7 @@ module RuboCop
50
50
  return unless self.class.supported?
51
51
 
52
52
  method, _args, body = *node
53
- return unless body && body.begin_type?
53
+ return unless body&.begin_type?
54
54
 
55
55
  _receiver, method_name, _object = *method
56
56
  return unless GROUP_BLOCKS.include?(method_name)
@@ -120,7 +120,7 @@ module RuboCop
120
120
  end
121
121
 
122
122
  def oneliner?(node)
123
- node && node.block_type? &&
123
+ node&.block_type? &&
124
124
  (node.source.lines.size == 1) &&
125
125
  example_node?(node)
126
126
  end
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
3
  require "test_prof/factory_bot"
5
4
 
6
- using TestProf::StringStripHeredoc
7
-
8
5
  module TestProf::EventProf::CustomEvents
9
6
  module FactoryCreate # :nodoc: all
10
7
  module RunnerPatch
@@ -49,7 +46,7 @@ TestProf::EventProf::CustomEvents.register("factory.create") do
49
46
  TestProf::EventProf::CustomEvents::FactoryCreate.setup!
50
47
  else
51
48
  TestProf.log(:error,
52
- <<-MSG.strip_heredoc
49
+ <<~MSG
53
50
  Failed to load factory_bot / factory_girl.
54
51
 
55
52
  Make sure that any of them is in your Gemfile.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
- using TestProf::StringStripHeredoc
6
-
7
3
  module TestProf::EventProf::CustomEvents
8
4
  module SidekiqInline # :nodoc: all
9
5
  module ClientPatch
@@ -43,7 +39,7 @@ end
43
39
  TestProf::EventProf::CustomEvents.register("sidekiq.inline") do
44
40
  if TestProf.require(
45
41
  'sidekiq/testing',
46
- <<-MSG.strip_heredoc
42
+ <<~MSG
47
43
  Failed to load Sidekiq.
48
44
 
49
45
  Make sure that "sidekiq" gem is in your Gemfile.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
- using TestProf::StringStripHeredoc
6
-
7
3
  module TestProf::EventProf::CustomEvents
8
4
  module SidekiqJobs # :nodoc: all
9
5
  module ClientPatch
@@ -30,7 +26,7 @@ end
30
26
  TestProf::EventProf::CustomEvents.register("sidekiq.jobs") do
31
27
  if TestProf.require(
32
28
  'sidekiq/testing',
33
- <<-MSG.strip_heredoc
29
+ <<~MSG
34
30
  Failed to load Sidekiq.
35
31
 
36
32
  Make sure that "sidekiq" gem is in your Gemfile.
@@ -1,18 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  module EventProf
7
5
  # Wrap methods with instrumentation
8
6
  module Monitor
9
- using StringStripHeredoc
10
-
11
7
  class << self
12
8
  def call(mod, event, *mids)
13
9
  patch = Module.new do
14
10
  mids.each do |mid|
15
- module_eval <<-SRC.strip_heredoc, __FILE__, __LINE__
11
+ module_eval <<~SRC, __FILE__, __LINE__ + 1
16
12
  def #{mid}(*)
17
13
  TestProf::EventProf.instrumenter.instrument(
18
14
  '#{event}'
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
4
  require "test_prof/ext/string_truncate"
5
- require "test_prof/ext/string_strip_heredoc"
6
5
 
7
6
  module TestProf
8
7
  module EventProf
@@ -10,7 +9,6 @@ module TestProf
10
9
  include Logging
11
10
  using FloatDuration
12
11
  using StringTruncate
13
- using StringStripHeredoc
14
12
 
15
13
  NOTIFICATIONS = %i[
16
14
  example_group_started
@@ -60,7 +58,7 @@ module TestProf
60
58
  msgs = []
61
59
 
62
60
  msgs <<
63
- <<-MSG.strip_heredoc
61
+ <<~MSG
64
62
  EventProf results for #{profiler.event}
65
63
 
66
64
  Total time: #{profiler.total_time.duration}
@@ -75,7 +73,7 @@ module TestProf
75
73
  location = group[:id].metadata[:location]
76
74
 
77
75
  msgs <<
78
- <<-GROUP.strip_heredoc
76
+ <<~GROUP
79
77
  #{description.truncate} (#{location}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
80
78
  GROUP
81
79
  end
@@ -87,7 +85,7 @@ module TestProf
87
85
  description = example[:id].description
88
86
  location = example[:id].metadata[:location]
89
87
  msgs <<
90
- <<-GROUP.strip_heredoc
88
+ <<~GROUP
91
89
  #{description.truncate} (#{location}) – #{example[:time].duration} (#{example[:count]})
92
90
  GROUP
93
91
  end
@@ -118,7 +116,7 @@ module TestProf
118
116
  msgs = []
119
117
 
120
118
  msgs <<
121
- <<-MSG.strip_heredoc
119
+ <<~MSG
122
120
  RSpec Stamp results
123
121
 
124
122
  Total patches: #{stamper.total}
@@ -148,6 +146,6 @@ TestProf.activate('EVENT_PROF') do
148
146
  )
149
147
  end
150
148
 
151
- config.after(:suite) { listener.print unless listener.nil? }
149
+ config.after(:suite) { listener&.print }
152
150
  end
153
151
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'minitest/base_reporter'
4
4
  require 'test_prof/ext/float_duration'
5
- require 'test_prof/ext/string_strip_heredoc'
6
5
 
7
6
  module Minitest
8
7
  module TestProf # :nodoc:
@@ -17,9 +16,8 @@ module Minitest
17
16
 
18
17
  class FactoryDoctorReporter < BaseReporter # :nodoc:
19
18
  using ::TestProf::FloatDuration
20
- using ::TestProf::StringStripHeredoc
21
19
 
22
- SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'.freeze
20
+ SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
23
21
 
24
22
  def initialize(io = $stdout, options = {})
25
23
  super
@@ -65,7 +63,7 @@ module Minitest
65
63
  msgs = []
66
64
 
67
65
  msgs <<
68
- <<-MSG.strip_heredoc
66
+ <<~MSG
69
67
  FactoryDoctor report
70
68
 
71
69
  Total (potentially) bad examples: #{@count}
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf
7
6
  module FactoryDoctor
8
7
  class RSpecListener # :nodoc:
9
8
  include Logging
10
9
  using FloatDuration
11
- using StringStripHeredoc
12
10
 
13
- SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'.freeze
11
+ SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
14
12
 
15
13
  NOTIFICATIONS = %i[
16
14
  example_started
@@ -58,7 +56,7 @@ module TestProf
58
56
  msgs = []
59
57
 
60
58
  msgs <<
61
- <<-MSG.strip_heredoc
59
+ <<~MSG
62
60
  FactoryDoctor report
63
61
 
64
62
  Total (potentially) bad examples: #{@count}
@@ -100,7 +98,7 @@ module TestProf
100
98
  msgs = []
101
99
 
102
100
  msgs <<
103
- <<-MSG.strip_heredoc
101
+ <<~MSG
104
102
  RSpec Stamp results
105
103
 
106
104
  Total patches: #{stamper.total}
@@ -137,7 +135,7 @@ TestProf.activate('FDOC') do
137
135
  )
138
136
  end
139
137
 
140
- config.after(:suite) { listener.print unless listener.nil? }
138
+ config.after(:suite) { listener&.print }
141
139
  end
142
140
 
143
141
  RSpec.shared_context "factory_doctor:ignore", fd_ignore: true do
@@ -5,8 +5,8 @@ require "test_prof/utils/html_builder"
5
5
  module TestProf::FactoryProf
6
6
  module Printers
7
7
  module Flamegraph # :nodoc: all
8
- TEMPLATE = "flamegraph.template.html".freeze
9
- OUTPUT_NAME = "factory-flame.html".freeze
8
+ TEMPLATE = "flamegraph.template.html"
9
+ OUTPUT_NAME = "factory-flame.html"
10
10
 
11
11
  class << self
12
12
  include TestProf::Logging
@@ -1,20 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf::FactoryProf
6
4
  module Printers
7
5
  module Simple # :nodoc: all
8
6
  class << self
9
7
  include TestProf::Logging
10
- using TestProf::StringStripHeredoc
11
8
 
12
9
  def dump(result)
13
10
  return log(:info, "No factories detected") if result.raw_stats == {}
14
11
  msgs = []
15
12
 
16
13
  msgs <<
17
- <<-MSG.strip_heredoc
14
+ <<~MSG
18
15
  Factories usage
19
16
 
20
17
  total top-level name
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "./active_record_shared_connection"
2
4
 
3
5
  # One ❤️
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(RSpec)
2
4
  RSpec.shared_context "logging:verbose", log: true do
3
5
  around(:each) do |ex|
@@ -16,10 +18,13 @@ if defined?(RSpec)
16
18
 
17
19
  RSpec.shared_context "logging:active_record", log: :ar do
18
20
  around(:each) do |ex|
19
- logger = ActiveRecord::Base.logger
20
- ActiveRecord::Base.logger = Logger.new(STDOUT)
21
+ *loggers = ActiveRecord::Base.logger,
22
+ ActiveSupport::LogSubscriber.logger
23
+ ActiveSupport::LogSubscriber.logger =
24
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
21
25
  ex.run
22
- ActiveRecord::Base.logger = logger
26
+ ActiveSupport::LogSubscriber.logger,
27
+ ActiveRecord::Base.logger = *loggers
23
28
  end
24
29
  end
25
30
  end
@@ -33,5 +38,6 @@ end
33
38
 
34
39
  TestProf.activate("LOG", "ar") do
35
40
  TestProf.log :info, "Active Record verbose logging enabled"
36
- ActiveRecord::Base.logger = Logger.new(STDOUT)
41
+ ActiveSupport::LogSubscriber.logger =
42
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
37
43
  end
@@ -9,7 +9,7 @@ module TestProf
9
9
  module LetItBe
10
10
  class << self
11
11
  def module_for(group)
12
- modules.fetch(group) do
12
+ modules[group] ||= begin
13
13
  Module.new.tap { |mod| group.prepend(mod) }
14
14
  end
15
15
  end
@@ -28,7 +28,7 @@ module TestProf
28
28
  # Use uniq prefix for instance variables to avoid collisions
29
29
  # We want to use the power of Ruby's unicode support)
30
30
  # And we love cats!)
31
- PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__".freeze : "@😸".freeze
31
+ PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__" : "@😸"
32
32
 
33
33
  def let_it_be(identifier, **options, &block)
34
34
  unless LetItBe.supported?
@@ -3,12 +3,10 @@
3
3
  require "test_prof/utils/sized_ordered_set"
4
4
  require "test_prof/ext/float_duration"
5
5
  require "test_prof/ext/string_truncate"
6
- require "test_prof/ext/string_strip_heredoc"
7
6
 
8
7
  module TestProf # :nodoc: all
9
8
  using FloatDuration
10
9
  using StringTruncate
11
- using StringStripHeredoc
12
10
 
13
11
  module RSpecDissect
14
12
  module Collectors
@@ -44,7 +42,7 @@ module TestProf # :nodoc: all
44
42
  end
45
43
 
46
44
  def print_result_header
47
- <<-MSG.strip_heredoc
45
+ <<~MSG
48
46
 
49
47
  Top #{top_count} slowest suites (by `#{print_name}` time):
50
48
 
@@ -52,7 +50,7 @@ module TestProf # :nodoc: all
52
50
  end
53
51
 
54
52
  def print_group_result(group)
55
- <<-GROUP.strip_heredoc
53
+ <<~GROUP
56
54
  #{group[:desc].truncate} (#{group[:loc]}) – #{group[name].duration} of #{group[:total].duration} (#{group[:count]})
57
55
  GROUP
58
56
  end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf
7
6
  module RSpecDissect
8
7
  class Listener # :nodoc:
9
8
  include Logging
10
9
  using FloatDuration
11
- using StringStripHeredoc
12
10
 
13
11
  NOTIFICATIONS = %i[
14
12
  example_group_finished
@@ -63,7 +61,7 @@ module TestProf
63
61
  msgs = []
64
62
 
65
63
  msgs <<
66
- <<-MSG.strip_heredoc
64
+ <<~MSG
67
65
  RSpecDissect report
68
66
 
69
67
  Total time: #{@total_examples_time.duration}
@@ -104,7 +102,7 @@ module TestProf
104
102
  msgs = []
105
103
 
106
104
  msgs <<
107
- <<-MSG.strip_heredoc
105
+ <<~MSG
108
106
  RSpec Stamp results
109
107
 
110
108
  Total patches: #{stamper.total}
@@ -141,6 +139,6 @@ TestProf.activate('RD_PROF') do
141
139
  )
142
140
  end
143
141
 
144
- config.after(:suite) { listener.print unless listener.nil? }
142
+ config.after(:suite) { listener&.print }
145
143
  end
146
144
  end
@@ -22,8 +22,8 @@ module TestProf
22
22
  end
23
23
 
24
24
  def remove_tag(tag)
25
- @tags.delete(tag) if @tags
26
- @htags.delete_if { |(k, _v)| k == tag } if @htags
25
+ @tags&.delete(tag)
26
+ @htags&.delete_if { |(k, _v)| k == tag }
27
27
  end
28
28
  end
29
29
 
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  module RSpecStamp
7
5
  class RSpecListener # :nodoc:
8
6
  include Logging
9
- using StringStripHeredoc
10
7
 
11
8
  NOTIFICATIONS = %i[
12
9
  example_failed
@@ -39,7 +36,7 @@ module TestProf
39
36
  msgs = []
40
37
 
41
38
  msgs <<
42
- <<-MSG.strip_heredoc
39
+ <<~MSG
43
40
  RSpec Stamp results
44
41
 
45
42
  Total patches: #{stamper.total}
@@ -67,6 +64,6 @@ TestProf.activate('RSTAMP') do
67
64
  )
68
65
  end
69
66
 
70
- config.after(:suite) { listener.stamp! unless listener.nil? }
67
+ config.after(:suite) { listener&.stamp! }
71
68
  end
72
69
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  # RubyProf wrapper.
7
5
  #
@@ -24,17 +22,6 @@ module TestProf
24
22
  module RubyProf
25
23
  # RubyProf configuration
26
24
  class Configuration
27
- # Default list of methods to exclude from profile.
28
- # Contains a lot of RSpec stuff.
29
- ELIMINATE_METHODS = [
30
- /instance_exec/,
31
- /ExampleGroup>?#run/,
32
- /Procsy/,
33
- /AroundHook#execute_with/,
34
- /HookCollections/,
35
- /Array#(map|each)/
36
- ].freeze
37
-
38
25
  PRINTERS = {
39
26
  'flat' => 'FlatPrinter',
40
27
  'flat_wln' => 'FlatPrinterWithLineNumbers',
@@ -56,10 +43,12 @@ module TestProf
56
43
  'call_stack' => 'html'
57
44
  }.freeze
58
45
 
59
- LOGFILE_PREFIX = "ruby-prof-report".freeze
46
+ LOGFILE_PREFIX = "ruby-prof-report"
60
47
 
61
48
  attr_accessor :printer, :mode, :min_percent,
62
- :include_threads, :eliminate_methods
49
+ :include_threads, :exclude_common_methods,
50
+ :test_prof_exclusions_enabled,
51
+ :custom_exclusions
63
52
 
64
53
  def initialize
65
54
  @printer = ENV['TEST_RUBY_PROF'].to_sym if PRINTERS.key?(ENV['TEST_RUBY_PROF'])
@@ -67,16 +56,21 @@ module TestProf
67
56
  @mode = ENV.fetch('TEST_RUBY_PROF_MODE', :wall).to_sym
68
57
  @min_percent = 1
69
58
  @include_threads = false
70
- @eliminate_methods = ELIMINATE_METHODS
59
+ @exclude_common_methods = true
60
+ @test_prof_exclusions_enabled = true
61
+ @custom_exclusions = {}
71
62
  end
72
63
 
73
64
  def include_threads?
74
65
  include_threads == true
75
66
  end
76
67
 
77
- def eliminate_methods?
78
- !eliminate_methods.nil? &&
79
- !eliminate_methods.empty?
68
+ def exclude_common_methods?
69
+ exclude_common_methods == true
70
+ end
71
+
72
+ def test_prof_exclusions_enabled?
73
+ @test_prof_exclusions_enabled == true
80
74
  end
81
75
 
82
76
  # Returns an array of printer type (ID) and class.
@@ -105,9 +99,6 @@ module TestProf
105
99
  def dump(name)
106
100
  result = @profiler.stop
107
101
 
108
- result.eliminate_methods!(config.eliminate_methods) if
109
- config.eliminate_methods?
110
-
111
102
  printer_type, printer_class = config.resolve_printer
112
103
 
113
104
  if %w[call_tree multi].include?(printer_type)
@@ -145,7 +136,6 @@ module TestProf
145
136
 
146
137
  class << self
147
138
  include Logging
148
- using StringStripHeredoc
149
139
 
150
140
  def config
151
141
  @config ||= Configuration.new
@@ -183,6 +173,20 @@ module TestProf
183
173
  config.include_threads?
184
174
 
185
175
  profiler = ::RubyProf::Profile.new(options)
176
+ profiler.exclude_common_methods! if config.exclude_common_methods?
177
+
178
+ if config.test_prof_exclusions_enabled?
179
+ # custom test-prof exclusions
180
+ exclude_rspec_methods(profiler)
181
+
182
+ # custom global exclusions
183
+ exclude_common_methods(profiler)
184
+ end
185
+
186
+ config.custom_exclusions.each do |klass, mids|
187
+ profiler.exclude_methods! klass, *mids
188
+ end
189
+
186
190
  profiler.start
187
191
 
188
192
  Report.new(profiler)
@@ -199,7 +203,7 @@ module TestProf
199
203
  ENV["RUBY_PROF_MEASURE_MODE"] = config.mode.to_s
200
204
  @initialized = TestProf.require(
201
205
  'ruby-prof',
202
- <<-MSG.strip_heredoc
206
+ <<~MSG
203
207
  Please, install 'ruby-prof' first:
204
208
  # Gemfile
205
209
  gem 'ruby-prof', '>= 0.16.0', require: false
@@ -208,20 +212,49 @@ module TestProf
208
212
  end
209
213
 
210
214
  def check_ruby_prof_version
211
- if Utils.verify_gem_version('ruby-prof', at_least: '0.16.0')
215
+ if Utils.verify_gem_version('ruby-prof', at_least: '0.17.0')
212
216
  true
213
217
  else
214
- log :error, <<-MGS.strip_heredoc
215
- Please, upgrade 'ruby-prof' to version >= 0.16.0.
218
+ log :error, <<~MGS
219
+ Please, upgrade 'ruby-prof' to version >= 0.17.0.
216
220
  MGS
217
221
  false
218
222
  end
219
223
  end
224
+
225
+ def exclude_rspec_methods(profiler)
226
+ return unless defined?(RSpec::Core)
227
+
228
+ RSpecExclusions.generate.each do |klass, mids|
229
+ profiler.exclude_methods!(klass, *mids)
230
+ end
231
+ end
232
+
233
+ def exclude_common_methods(profiler)
234
+ profiler.exclude_methods!(
235
+ TSort,
236
+ :tsort_each
237
+ )
238
+
239
+ profiler.exclude_methods!(
240
+ TSort.singleton_class,
241
+ :tsort_each, :each_strongly_connected_component,
242
+ :each_strongly_connected_component_from
243
+ )
244
+
245
+ profiler.exclude_methods!(
246
+ BasicObject,
247
+ :instance_exec
248
+ )
249
+ end
220
250
  end
221
251
  end
222
252
  end
223
253
 
224
- require "test_prof/ruby_prof/rspec" if defined?(RSpec::Core)
254
+ if defined?(RSpec::Core)
255
+ require "test_prof/ruby_prof/rspec"
256
+ require "test_prof/ruby_prof/rspec_exclusions"
257
+ end
225
258
 
226
259
  # Hook to run RubyProf globally
227
260
  TestProf.activate('TEST_RUBY_PROF') do
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module RubyProf
5
+ # Generates the list of RSpec (framework internal) methods
6
+ # to exclude from profiling
7
+ module RSpecExclusions
8
+ module_function
9
+
10
+ def generate
11
+ {
12
+ RSpec::Core::Runner => %i[
13
+ run
14
+ run_specs
15
+ ],
16
+
17
+ RSpec::Core::ExampleGroup => %i[
18
+ run
19
+ run_examples
20
+ ],
21
+
22
+ RSpec::Core::ExampleGroup.singleton_class => %i[
23
+ run
24
+ run_examples
25
+ ],
26
+
27
+ RSpec::Core::Example => %i[
28
+ run
29
+ with_around_and_singleton_context_hooks
30
+ with_around_example_hooks
31
+ instance_exec
32
+ run_before_example
33
+ ],
34
+
35
+ RSpec::Core::Example.singleton_class => %i[
36
+ run
37
+ with_around_and_singleton_context_hooks
38
+ with_around_example_hooks
39
+ ],
40
+
41
+ RSpec::Core::Example::Procsy => [
42
+ :call
43
+ ],
44
+
45
+ RSpec::Core::Hooks::HookCollections => %i[
46
+ run
47
+ run_around_example_hooks_for
48
+ run_example_hooks_for
49
+ run_owned_hooks_for
50
+ ],
51
+
52
+ RSpec::Core::Hooks::BeforeHook => [
53
+ :run
54
+ ],
55
+
56
+ RSpec::Core::Hooks::AroundHook => [
57
+ :execute_with
58
+ ],
59
+
60
+ RSpec::Core::Configuration => [
61
+ :with_suite_hooks
62
+ ],
63
+
64
+ RSpec::Core::Reporter => [
65
+ :report
66
+ ]
67
+ }.tap do |data|
68
+ if defined?(RSpec::Support::ReentrantMutex)
69
+ data[RSpec::Support::ReentrantMutex] = [
70
+ :synchronize
71
+ ]
72
+ end
73
+
74
+ if defined?(RSpec::Core::MemoizedHelpers::ThreadsafeMemoized)
75
+ data.merge!(
76
+ RSpec::Core::MemoizedHelpers::ThreadsafeMemoized => [
77
+ :fetch_or_store
78
+ ],
79
+
80
+ RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized => [
81
+ :fetch_or_store
82
+ ],
83
+
84
+ RSpec::Core::MemoizedHelpers::ContextHookMemoized => [
85
+ :fetch_or_store
86
+ ]
87
+ )
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "test_prof/ext/string_strip_heredoc"
4
-
5
3
  module TestProf
6
4
  # StackProf wrapper.
7
5
  #
@@ -47,7 +45,6 @@ module TestProf
47
45
 
48
46
  class << self
49
47
  include Logging
50
- using StringStripHeredoc
51
48
 
52
49
  def config
53
50
  @config ||= Configuration.new
@@ -103,7 +100,7 @@ module TestProf
103
100
 
104
101
  html_path = path.gsub(/\.dump$/, '.html')
105
102
 
106
- log :info, <<-MSG.strip_heredoc
103
+ log :info, <<~MSG
107
104
  Run the following command to generate a flame graph report:
108
105
 
109
106
  stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
@@ -126,7 +123,7 @@ module TestProf
126
123
  return @initialized if instance_variable_defined?(:@initialized)
127
124
  @initialized = TestProf.require(
128
125
  'stackprof',
129
- <<-MSG.strip_heredoc
126
+ <<~MSG
130
127
  Please, install 'stackprof' first:
131
128
  # Gemfile
132
129
  gem 'stackprof', '>= 0.2.9', require: false
@@ -138,7 +135,7 @@ module TestProf
138
135
  if Utils.verify_gem_version('stackprof', at_least: '0.2.9')
139
136
  true
140
137
  else
141
- log :error, <<-MSG.strip_heredoc
138
+ log :error, <<~MSG
142
139
  Please, upgrade 'stackprof' to version >= 0.2.9.
143
140
  MSG
144
141
  false
@@ -3,8 +3,8 @@
3
3
  module TestProf::TagProf
4
4
  module Printers
5
5
  module HTML # :nodoc: all
6
- TEMPLATE = "tagprof.template.html".freeze
7
- OUTPUT_NAME = "tag-prof.html".freeze
6
+ TEMPLATE = "tagprof.template.html"
7
+ OUTPUT_NAME = "tag-prof.html"
8
8
 
9
9
  class << self
10
10
  include TestProf::Logging
@@ -1,21 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/ext/float_duration"
4
- require "test_prof/ext/string_strip_heredoc"
5
4
 
6
5
  module TestProf::TagProf
7
6
  module Printers
8
7
  module Simple # :nodoc: all
9
8
  class << self
10
9
  include TestProf::Logging
11
- using TestProf::StringStripHeredoc
12
10
  using TestProf::FloatDuration
13
11
 
14
12
  def dump(result)
15
13
  msgs = []
16
14
 
17
15
  msgs <<
18
- <<-MSG.strip_heredoc
16
+ <<~MSG
19
17
  TagProf report for #{result.tag}
20
18
  MSG
21
19
 
@@ -33,7 +33,7 @@ module TestProf
33
33
  def example_started(_notification)
34
34
  @ts = TestProf.now
35
35
  # enable event profiling
36
- @events_profiler.group_started(true) if @events_profiler
36
+ @events_profiler&.group_started(true)
37
37
  end
38
38
 
39
39
  def example_finished(notification)
@@ -42,7 +42,7 @@ module TestProf
42
42
  result.track(tag, time: TestProf.now - @ts, events: fetch_events_data)
43
43
 
44
44
  # reset and disable event profilers
45
- @events_profiler.group_started(nil) if @events_profiler
45
+ @events_profiler&.group_started(nil)
46
46
  end
47
47
 
48
48
  # NOTE: RSpec < 3.4.0 doesn't have example_finished event
@@ -80,7 +80,7 @@ TestProf.activate('TAG_PROF') do
80
80
  )
81
81
  end
82
82
 
83
- config.after(:suite) { listener.report unless listener.nil? }
83
+ config.after(:suite) { listener&.report }
84
84
  end
85
85
  end
86
86
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.6.0".freeze
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-29 00:00:00.000000000 Z
11
+ date: 2018-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.57.0
75
+ version: 0.58.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.57.0
82
+ version: 0.58.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubocop-md
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -142,7 +142,6 @@ files:
142
142
  - lib/test_prof/ext/active_record_refind.rb
143
143
  - lib/test_prof/ext/array_bsearch_index.rb
144
144
  - lib/test_prof/ext/float_duration.rb
145
- - lib/test_prof/ext/string_strip_heredoc.rb
146
145
  - lib/test_prof/ext/string_truncate.rb
147
146
  - lib/test_prof/factory_all_stub.rb
148
147
  - lib/test_prof/factory_all_stub/factory_bot_patch.rb
@@ -183,6 +182,7 @@ files:
183
182
  - lib/test_prof/rubocop.rb
184
183
  - lib/test_prof/ruby_prof.rb
185
184
  - lib/test_prof/ruby_prof/rspec.rb
185
+ - lib/test_prof/ruby_prof/rspec_exclusions.rb
186
186
  - lib/test_prof/stack_prof.rb
187
187
  - lib/test_prof/stack_prof/rspec.rb
188
188
  - lib/test_prof/tag_prof.rb
@@ -206,7 +206,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
206
  requirements:
207
207
  - - ">="
208
208
  - !ruby/object:Gem::Version
209
- version: 2.2.0
209
+ version: 2.3.0
210
210
  required_rubygems_version: !ruby/object:Gem::Requirement
211
211
  requirements:
212
212
  - - ">="
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TestProf
4
- # Add #strip_heredoc method to use instead of
5
- # squiggly docs (to support older Rubies)
6
- module StringStripHeredoc
7
- refine String do
8
- def strip_heredoc
9
- min = scan(/^[ \t]*(?=\S)/).min
10
- indent = min ? min.size : 0
11
- gsub(/^[ \t]{#{indent}}/, '')
12
- end
13
- end
14
- end
15
- end