test-prof 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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