test-prof 1.3.0 → 1.4.4

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -0
  3. data/README.md +2 -2
  4. data/lib/minitest/test_prof_plugin.rb +3 -0
  5. data/lib/test_prof/any_fixture/dsl.rb +19 -1
  6. data/lib/test_prof/any_fixture/dump.rb +1 -1
  7. data/lib/test_prof/any_fixture.rb +16 -2
  8. data/lib/test_prof/before_all/adapters/active_record.rb +82 -47
  9. data/lib/test_prof/before_all/isolator.rb +6 -15
  10. data/lib/test_prof/before_all.rb +31 -8
  11. data/lib/test_prof/cops/rspec/aggregate_examples/its.rb +2 -2
  12. data/lib/test_prof/cops/rspec/aggregate_examples/line_range_helpers.rb +1 -1
  13. data/lib/test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects.rb +1 -1
  14. data/lib/test_prof/cops/rspec/aggregate_examples/metadata_helpers.rb +1 -1
  15. data/lib/test_prof/cops/rspec/aggregate_examples/node_matchers.rb +1 -1
  16. data/lib/test_prof/cops/rspec/aggregate_examples.rb +12 -18
  17. data/lib/test_prof/core.rb +28 -1
  18. data/lib/test_prof/event_prof/monitor.rb +3 -10
  19. data/lib/test_prof/ext/active_record_refind.rb +1 -1
  20. data/lib/test_prof/ext/string_truncate.rb +1 -1
  21. data/lib/test_prof/factory_bot.rb +2 -0
  22. data/lib/test_prof/factory_default/fabrication_patch.rb +60 -0
  23. data/lib/test_prof/factory_default/factory_bot_patch.rb +59 -9
  24. data/lib/test_prof/factory_default.rb +11 -39
  25. data/lib/test_prof/factory_doctor.rb +1 -2
  26. data/lib/test_prof/factory_prof/fabrication_patch.rb +7 -1
  27. data/lib/test_prof/factory_prof/factory_bot_patch.rb +15 -1
  28. data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +2 -2
  29. data/lib/test_prof/factory_prof/factory_builders/factory_bot.rb +2 -2
  30. data/lib/test_prof/factory_prof/printers/json.rb +41 -0
  31. data/lib/test_prof/factory_prof/printers/nate_heckler.rb +1 -1
  32. data/lib/test_prof/factory_prof/printers/simple.rb +23 -4
  33. data/lib/test_prof/factory_prof.rb +57 -25
  34. data/lib/test_prof/memory_prof/printer.rb +2 -0
  35. data/lib/test_prof/memory_prof/rspec.rb +7 -4
  36. data/lib/test_prof/memory_prof/tracker/linked_list.rb +8 -6
  37. data/lib/test_prof/memory_prof/tracker.rb +14 -10
  38. data/lib/test_prof/recipes/minitest/before_all.rb +2 -2
  39. data/lib/test_prof/recipes/minitest/sample.rb +14 -5
  40. data/lib/test_prof/recipes/rspec/any_fixture.rb +8 -0
  41. data/lib/test_prof/recipes/rspec/let_it_be.rb +19 -0
  42. data/lib/test_prof/rspec_stamp/parser.rb +1 -1
  43. data/lib/test_prof/rspec_stamp.rb +7 -5
  44. data/lib/test_prof/ruby_prof/rspec_no_boot.rb +15 -0
  45. data/lib/test_prof/ruby_prof.rb +20 -7
  46. data/lib/test_prof/tag_prof/minitest.rb +74 -0
  47. data/lib/test_prof/tag_prof/result.rb +2 -2
  48. data/lib/test_prof/tps_prof/profiler.rb +55 -0
  49. data/lib/test_prof/tps_prof/reporter/text.rb +48 -0
  50. data/lib/test_prof/tps_prof/rspec.rb +63 -0
  51. data/lib/test_prof/tps_prof.rb +46 -0
  52. data/lib/test_prof/vernier.rb +3 -1
  53. data/lib/test_prof/version.rb +1 -1
  54. data/lib/test_prof.rb +1 -0
  55. metadata +15 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0678bc968a267ebeece00e12338f6408683140428ecdd041ece64c70e6bb91c0'
4
- data.tar.gz: 3ab5bc88b7b5dea557847f05a16d7fc3e4c6c9212115cd16984a56b7dd7b1737
3
+ metadata.gz: 3cfa0f1751f398092de8ffa46d5bff81bb9eadd7b90caaf9293c62c93c6b3e20
4
+ data.tar.gz: 3afcb831782f0e58881839f33af07a41b3b42d63ac8eb87c35b6fd0eb01537ea
5
5
  SHA512:
6
- metadata.gz: 5b32e7e689cef27e72ce5f7e65ca0463bae7b83dfcaf77eba17aa0cc9bae1b74d6223b6b141e805debb7640b74b75be34bf238a8f41cb3efaf0386929935d814
7
- data.tar.gz: 34200774bc30c39acc48109fbc5031fd8f48abb5f7175799a1e1bbfd7650a11a441c9ba63638bf186d78ef5cd15b7b33e64782c781a7f28bd43e43cb6d1e5588
6
+ metadata.gz: 2de8fb8232f5ed623167846c37cce6224b297761324acdf6a17a47338e2a3904aa480b48fc9793a51f5595d3d839c3ff3bc9fbb262c7900ad3d7c819113947a0
7
+ data.tar.gz: dcec92d722f9e7cce9f1d371a2c6d363aa9a78a6cf1149a73d8b836a269ebf6bd14e50d86a8470cccc56a861b94646ad23494f43de6d9beb0cc6a5b478f77e93
data/CHANGELOG.md CHANGED
@@ -2,6 +2,78 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 1.4.4 (2025-01-03)
6
+
7
+ - Fix _stamping_ specs with single quotes with Rpsec Stamp. ([@elasticspoon][])
8
+
9
+ ## 1.4.3 (2024-12-18)
10
+
11
+ - Fix handling new (lazy) connection pools in `before_all`. ([@palkan][])
12
+
13
+ - Updates Rubocop::Cop code to comply with most modern API. ([@aseroff][])
14
+
15
+ ## 1.4.2 (2024-09-03) 🗓️
16
+
17
+ - Ignore default scopes in `ActiveRecord::Base#refind`. ([@palkan][])
18
+
19
+ ## 1.4.1 (2024-08-23)
20
+
21
+ - Skips loading the ActiveRecord adapter for runs where RSpec --dry-run mode is enabled. ([@devinburnette][])
22
+
23
+ ## 1.4.0 (2024-08-12)
24
+
25
+ - AnyFixture: Disable fixtures cache within _clean fixture_ context. Automatically _refind_ records when using `#fixture`. ([@palkan][])
26
+
27
+ - Add new TPS (tests per second) profiler. ([@palkan][])
28
+
29
+ - FactoryDefault: add Fabrication support. ([@palkan][])
30
+
31
+ - Drop support for **Ruby <2.7** and **Rails <6**.
32
+
33
+ - FactoryDefault: Add `#get_factory_default`. [[@john-h-k][]]
34
+
35
+ - Add variations information to FactorProf reports. ([@lHydra][])
36
+
37
+ Get info on traits/overrides used by running `FPROF=1 FPROF_VARS=1 <your test command>`.
38
+
39
+ - Add support for `report_duplicates` config option for `let_it_be` ([@lHydra][])
40
+
41
+ - Support latest Timecop patching `Process.clock_gettime`. ([@palkan][])
42
+
43
+ - Vernier: Add hooks configuration parameter. ([@lHydra][])
44
+
45
+ Now you can add more insights to the resulting report by adding event markers from Active Support Notifications.
46
+ To do this, specify the `TEST_VERNIER_HOOKS=rails` env var or set it through `Vernier` configuration:
47
+
48
+ ```ruby
49
+ TestProf::Vernier.configure do |config|
50
+ config.hooks = :rails
51
+ end
52
+ ```
53
+
54
+ - FactoryProf: Add threshold configuration parameter. ([@lHydra][])
55
+
56
+ Now you can ignore factories which total number of calls is less than the provided threshold. To do this, specify
57
+ the `FPROF_THRESHOLD=30` env var or set it through `FactoryProf` configuration:
58
+
59
+ ```ruby
60
+ TestProf::FactoryProf.configure do |config|
61
+ config.threshold = 30
62
+ end
63
+ ```
64
+
65
+ ## 1.3.3 (2024-04-19)
66
+
67
+ - Fix MemProf bugs. ([@palkan][])
68
+
69
+ ## 1.3.2 (2024-03-08) 🌷
70
+
71
+ - Add Minitest support for TagProf. ([@lioneldebauge][])
72
+
73
+ ## 1.3.1 (2023-12-12)
74
+
75
+ - Add support for dumping FactoryProf results in JSON format. ([@uzushino][])
76
+
5
77
  ## 1.3.0 (2023-11-21)
6
78
 
7
79
  - Add Vernier integration. ([@palkan][])
@@ -376,3 +448,9 @@ See [changelog](https://github.com/test-prof/test-prof/blob/v0.8.0/CHANGELOG.md)
376
448
  [@peret]: https://github.com/peret
377
449
  [@bf4]: https://github.com/bf4
378
450
  [@Vankiru]: https://github.com/Vankiru
451
+ [@uzushino]: https://github.com/uzushino
452
+ [@lioneldebauge]: https://github.com/lioneldebauge
453
+ [@lHydra]: https://github.com/lHydra
454
+ [@john-h-k]: https://github.com/john-h-k
455
+ [@devinburnette]: https://github.com/devinburnette
456
+ [@elasticspoon]: https://github.com/elasticspoon
data/README.md CHANGED
@@ -83,9 +83,9 @@ And that's it)
83
83
 
84
84
  Supported Ruby versions:
85
85
 
86
- - Ruby (MRI) >= 2.5.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0, Ruby 2.3 use TestProf ~> 0.7.0, Ruby 2.4 use TestProf <0.12.0)
86
+ - Ruby (MRI) >= 2.7.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0, Ruby 2.3 use TestProf ~> 0.7.0, Ruby 2.4 use TestProf <0.12.0, Ruby 2.5-2.6 use TestProf < 1.3)
87
87
 
88
- - JRuby >= 9.1.0.0 (**NOTE:** refinements-dependent features might require 9.2.7+)
88
+ - JRuby >= 9.3.0
89
89
 
90
90
  Supported RSpec version (for RSpec features only): >= 3.5.0 (for older RSpec versions use TestProf < 0.8.0).
91
91
 
@@ -3,6 +3,7 @@
3
3
  require "test_prof/event_prof/minitest"
4
4
  require "test_prof/factory_doctor/minitest"
5
5
  require "test_prof/memory_prof/minitest"
6
+ require "test_prof/tag_prof/minitest"
6
7
 
7
8
  module Minitest # :nodoc:
8
9
  module TestProf # :nodoc:
@@ -16,6 +17,7 @@ module Minitest # :nodoc:
16
17
  opts[:sample] = true if ENV["SAMPLE"] || ENV["SAMPLE_GROUPS"]
17
18
  opts[:mem_prof_mode] = ENV["TEST_MEM_PROF"] if ENV["TEST_MEM_PROF"]
18
19
  opts[:mem_prof_top_count] = ENV["TEST_MEM_PROF_COUNT"] if ENV["TEST_MEM_PROF_COUNT"]
20
+ opts[:tag_prof] = true if ENV["TAG_PROF"] == "type"
19
21
  end
20
22
  end
21
23
  end
@@ -50,6 +52,7 @@ module Minitest # :nodoc:
50
52
  reporter << TestProf::EventProfReporter.new(options[:io], options) if options[:event]
51
53
  reporter << TestProf::FactoryDoctorReporter.new(options[:io], options) if options[:fdoc]
52
54
  reporter << TestProf::MemoryProfReporter.new(options[:io], options) if options[:mem_prof_mode]
55
+ reporter << Minitest::TestProf::TagProfReporter.new(options[:io], options) if options[:tag_prof]
53
56
 
54
57
  ::TestProf::MinitestSample.call if options[:sample]
55
58
  end
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if defined?(::ActiveRecord::Base)
4
+ require "test_prof/ext/active_record_refind"
5
+ using TestProf::Ext::ActiveRecordRefind
6
+ end
7
+
3
8
  module TestProf
4
9
  module AnyFixture
5
10
  # Adds "global" `fixture`, `before_fixtures_reset` and `after_fixtures_reset` methods (through refinement)
@@ -9,7 +14,20 @@ module TestProf
9
14
  # - Rails added `Kernel.prepend` in 6.1: https://github.com/rails/rails/commit/3124007bd674dcdc9c3b5c6b2964dfb7a1a0733c
10
15
  refine ::Object do
11
16
  def fixture(id, &block)
12
- ::TestProf::AnyFixture.register(:"#{id}", &block)
17
+ id = :"#{id}"
18
+ record = ::TestProf::AnyFixture.cached(id)
19
+
20
+ return ::TestProf::AnyFixture.register(id, &block) unless record
21
+
22
+ return record.refind if record.is_a?(::ActiveRecord::Base)
23
+
24
+ if record.respond_to?(:to_ary)
25
+ return record.map do |rec|
26
+ rec.is_a?(::ActiveRecord::Base) ? rec.refind : rec
27
+ end
28
+ end
29
+
30
+ record
13
31
  end
14
32
 
15
33
  def before_fixtures_reset(&block)
@@ -69,7 +69,7 @@ module TestProf
69
69
  end
70
70
 
71
71
  def commit
72
- return unless defined?(:@file)
72
+ return unless instance_variable_defined?(:@file)
73
73
 
74
74
  file.close
75
75
 
@@ -108,14 +108,18 @@ module TestProf
108
108
  cached(id) do
109
109
  raise "No fixture named #{id} has been registered" unless block_given?
110
110
 
111
+ next yield if @disabled
112
+
111
113
  ActiveSupport::Notifications.subscribed(method(:subscriber), "sql.active_record") do
112
114
  yield
113
115
  end
114
116
  end
115
117
  end
116
118
 
117
- def cached(id)
118
- cache.fetch(id) { yield }
119
+ def cached(id, &block)
120
+ return (block_given? ? yield : nil) if @disabled
121
+
122
+ cache.fetch(id, &block)
119
123
  end
120
124
 
121
125
  # Create and register new SQL dump.
@@ -174,6 +178,14 @@ module TestProf
174
178
  callbacks.clear
175
179
  end
176
180
 
181
+ def disable!
182
+ @disabled = true
183
+ end
184
+
185
+ def enable!
186
+ @disabled = false
187
+ end
188
+
177
189
  def before_fixtures_reset(&block)
178
190
  callbacks[:before_fixtures_reset] << block
179
191
  end
@@ -266,5 +278,7 @@ module TestProf
266
278
  connection.disable_referential_integrity { yield }
267
279
  end
268
280
  end
281
+
282
+ enable!
269
283
  end
270
284
  end
@@ -8,44 +8,79 @@ module TestProf
8
8
  POOL_ARGS = ((::ActiveRecord::VERSION::MAJOR > 6) ? [:writing] : []).freeze
9
9
 
10
10
  class << self
11
- def all_connections
12
- @all_connections ||= if ::ActiveRecord::Base.respond_to? :connects_to
13
- ::ActiveRecord::Base.connection_handler.connection_pool_list(*POOL_ARGS).filter_map { |pool|
14
- begin
15
- pool.connection
16
- rescue *pool_connection_errors => error
17
- log_pool_connection_error(pool, error)
18
- nil
19
- end
20
- }
21
- else
22
- Array.wrap(::ActiveRecord::Base.connection)
11
+ if ::ActiveRecord::Base.connection.pool.respond_to?(:pin_connection!)
12
+ def begin_transaction
13
+ subscribe!
14
+ ::ActiveRecord::Base.connection_handler.connection_pool_list(:writing).each do |pool|
15
+ pool.pin_connection!(true)
16
+ end
23
17
  end
24
- end
25
18
 
26
- def pool_connection_errors
27
- @pool_connection_errors ||= []
28
- end
19
+ def rollback_transaction
20
+ ::ActiveRecord::Base.connection_handler.connection_pool_list(:writing).each do |pool|
21
+ pool.unpin_connection!
22
+ end
23
+ unsubscribe!
24
+ end
29
25
 
30
- def log_pool_connection_error(pool, error)
31
- warn "Could not connect to pool #{pool.connection_class.name}. #{error.class}: #{error.message}"
32
- end
26
+ def subscribe!
27
+ Thread.current[:before_all_connection_subscriber] = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
28
+ connection_name = payload[:connection_name] if payload.key?(:connection_name)
29
+ shard = payload[:shard] if payload.key?(:shard)
30
+ next unless connection_name
33
31
 
34
- def begin_transaction
35
- @all_connections = nil
36
- all_connections.each do |connection|
37
- connection.begin_transaction(joinable: false)
32
+ pool = ::ActiveRecord::Base.connection_handler.retrieve_connection_pool(connection_name, shard: shard)
33
+ next unless pool && pool.role == :writing
34
+
35
+ pool.pin_connection!(true)
36
+ end
38
37
  end
39
- end
40
38
 
41
- def rollback_transaction
42
- all_connections.each do |connection|
43
- if connection.open_transactions.zero?
44
- warn "!!! before_all transaction has been already rollbacked and " \
45
- "could work incorrectly"
46
- next
39
+ def unsubscribe!
40
+ return unless Thread.current[:before_all_connection_subscriber]
41
+ ActiveSupport::Notifications.unsubscribe(Thread.current[:before_all_connection_subscriber])
42
+ Thread.current[:before_all_connection_subscriber] = nil
43
+ end
44
+ else
45
+ def all_connections
46
+ @all_connections ||= if ::ActiveRecord::Base.respond_to? :connects_to
47
+ ::ActiveRecord::Base.connection_handler.connection_pool_list(*POOL_ARGS).filter_map { |pool|
48
+ begin
49
+ pool.connection
50
+ rescue *pool_connection_errors => error
51
+ log_pool_connection_error(pool, error)
52
+ nil
53
+ end
54
+ }
55
+ else
56
+ Array.wrap(::ActiveRecord::Base.connection)
57
+ end
58
+ end
59
+
60
+ def pool_connection_errors
61
+ @pool_connection_errors ||= []
62
+ end
63
+
64
+ def log_pool_connection_error(pool, error)
65
+ warn "Could not connect to pool #{pool.connection_class.name}. #{error.class}: #{error.message}"
66
+ end
67
+
68
+ def begin_transaction
69
+ @all_connections = nil
70
+ all_connections.each do |connection|
71
+ connection.begin_transaction(joinable: false)
72
+ end
73
+ end
74
+
75
+ def rollback_transaction
76
+ all_connections.each do |connection|
77
+ if connection.open_transactions.zero?
78
+ warn "!!! before_all transaction has been already rollbacked and " \
79
+ "could work incorrectly"
80
+ next
81
+ end
82
+ connection.rollback_transaction
47
83
  end
48
- connection.rollback_transaction
49
84
  end
50
85
  end
51
86
 
@@ -67,23 +102,23 @@ module TestProf
67
102
  end
68
103
  end
69
104
 
70
- # avoid instance variable collisions with cats
71
- PREFIX_RESTORE_LOCK_THREAD = "@😺"
72
-
73
- configure do |config|
74
- # Make sure ActiveRecord uses locked thread.
75
- # It only gets locked in `before` / `setup` hook,
76
- # thus using thread in `before_all` (e.g. ActiveJob async adapter)
77
- # might lead to leaking connections
78
- config.before(:begin) do
79
- next unless ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
80
- instance_variable_set("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread", ::ActiveRecord::Base.connection.pool.instance_variable_get(:@lock_thread)) unless instance_variable_defined? "#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread"
81
- ::ActiveRecord::Base.connection.pool.lock_thread = true
82
- end
105
+ unless ::ActiveRecord::Base.connection.pool.respond_to?(:pin_connection!)
106
+ # avoid instance variable collisions with cats
107
+ PREFIX_RESTORE_LOCK_THREAD = "@😺"
83
108
 
84
- config.after(:rollback) do
85
- next unless ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
86
- ::ActiveRecord::Base.connection.pool.lock_thread = instance_variable_get("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread")
109
+ configure do |config|
110
+ # Make sure ActiveRecord uses locked thread.
111
+ # It only gets locked in `before` / `setup` hook,
112
+ # thus using thread in `before_all` (e.g. ActiveJob async adapter)
113
+ # might lead to leaking connections
114
+ config.before(:begin) do
115
+ instance_variable_set("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread", ::ActiveRecord::Base.connection.pool.instance_variable_get(:@lock_thread)) unless instance_variable_defined? "#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread"
116
+ ::ActiveRecord::Base.connection.pool.lock_thread = true
117
+ end
118
+
119
+ config.after(:rollback) do
120
+ ::ActiveRecord::Base.connection.pool.lock_thread = instance_variable_get("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread")
121
+ end
87
122
  end
88
123
  end
89
124
  end
@@ -1,20 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module TestProf
4
- module BeforeAll
5
- # Disable Isolator within before_all blocks
6
- module Isolator
7
- def begin_transaction(*)
8
- ::Isolator.transactions_threshold += 1
9
- super
10
- end
3
+ TestProf::BeforeAll.configure do |config|
4
+ config.before(:begin) do
5
+ ::Isolator.incr_thresholds!
6
+ end
11
7
 
12
- def rollback_transaction(*)
13
- super
14
- ::Isolator.transactions_threshold -= 1
15
- end
16
- end
8
+ config.after(:rollback) do
9
+ ::Isolator.decr_thresholds!
17
10
  end
18
11
  end
19
-
20
- TestProf::BeforeAll.singleton_class.prepend(TestProf::BeforeAll::Isolator)
@@ -14,8 +14,26 @@ module TestProf
14
14
  end
15
15
  end
16
16
 
17
+ # Used in dry-run mode
18
+ class NoopAdapter
19
+ class << self
20
+ def begin_transaction(...)
21
+ end
22
+
23
+ def rollback_transaction(...)
24
+ end
25
+
26
+ def setup_fixtures(...)
27
+ end
28
+ end
29
+ end
30
+
17
31
  class << self
18
- attr_accessor :adapter
32
+ attr_writer :adapter
33
+
34
+ def adapter
35
+ @adapter ||= default_adapter
36
+ end
19
37
 
20
38
  def begin_transaction(scope = nil, metadata = [])
21
39
  raise AdapterMissing if adapter.nil?
@@ -47,6 +65,17 @@ module TestProf
47
65
  def configure
48
66
  yield config
49
67
  end
68
+
69
+ private
70
+
71
+ def default_adapter
72
+ return NoopAdapter if TestProf.dry_run?
73
+
74
+ if defined?(::ActiveRecord::Base)
75
+ require "test_prof/before_all/adapters/active_record"
76
+ Adapters::ActiveRecord
77
+ end
78
+ end
50
79
  end
51
80
 
52
81
  class HookEntry # :nodoc:
@@ -66,7 +95,7 @@ module TestProf
66
95
  private
67
96
 
68
97
  def filters_apply?(metadata)
69
- return true unless filters.present? && TestProf.rspec?
98
+ return true unless filters.is_a?(Hash) && TestProf.rspec?
70
99
 
71
100
  ::RSpec::Core::MetadataFilter.apply?(
72
101
  :all?,
@@ -138,12 +167,6 @@ module TestProf
138
167
  end
139
168
  end
140
169
 
141
- if defined?(::ActiveRecord::Base)
142
- require "test_prof/before_all/adapters/active_record"
143
-
144
- TestProf::BeforeAll.adapter = TestProf::BeforeAll::Adapters::ActiveRecord
145
- end
146
-
147
170
  if defined?(::Isolator)
148
171
  require "test_prof/before_all/isolator"
149
172
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- class AggregateExamples < ::RuboCop::Cop::Cop
6
+ class AggregateExamples < ::RuboCop::Cop::Base
7
7
  # @example `its`
8
8
  #
9
9
  # # Supports regular `its` call with an attribute/method name,
@@ -64,7 +64,7 @@ module RuboCop
64
64
  return super unless its?(example.send_node)
65
65
 
66
66
  # First parameter to `its` is not metadata.
67
- example.send_node.arguments[1..-1]
67
+ example.send_node.arguments[1..]
68
68
  end
69
69
 
70
70
  def its?(node)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- class AggregateExamples < ::RuboCop::Cop::Cop
6
+ class AggregateExamples < ::RuboCop::Cop::Base
7
7
  # @internal Support methods for keeping newlines around examples.
8
8
  module LineRangeHelpers
9
9
  include RangeHelp
@@ -5,7 +5,7 @@ require "test_prof/cops/rspec/language"
5
5
  module RuboCop
6
6
  module Cop
7
7
  module RSpec
8
- class AggregateExamples < ::RuboCop::Cop::Cop
8
+ class AggregateExamples < ::RuboCop::Cop::Base
9
9
  # When aggregated, the expectations will fail when not supposed to or
10
10
  # have a risk of not failing when expected to. One example is
11
11
  # `validate_presence_of :comment` as it leaves an empty comment after
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- class AggregateExamples < ::RuboCop::Cop::Cop
6
+ class AggregateExamples < ::RuboCop::Cop::Base
7
7
  # @internal
8
8
  # Support methods for example metadata.
9
9
  # Examples with similar metadata are grouped.
@@ -5,7 +5,7 @@ require "test_prof/cops/rspec/language"
5
5
  module RuboCop
6
6
  module Cop
7
7
  module RSpec
8
- class AggregateExamples < ::RuboCop::Cop::Cop
8
+ class AggregateExamples < ::RuboCop::Cop::Base
9
9
  # @internal
10
10
  # Node matchers and searchers.
11
11
  module NodeMatchers
@@ -108,7 +108,8 @@ module RuboCop
108
108
  # expect(number).to be_odd
109
109
  # end
110
110
  #
111
- class AggregateExamples < ::RuboCop::Cop::Cop
111
+ class AggregateExamples < ::RuboCop::Cop::Base
112
+ extend AutoCorrector
112
113
  include LineRangeHelpers
113
114
  include MetadataHelpers
114
115
  include NodeMatchers
@@ -123,29 +124,22 @@ module RuboCop
123
124
  def on_block(node)
124
125
  example_group_with_several_examples(node) do |all_examples|
125
126
  example_clusters(all_examples).each do |_, examples|
126
- examples[1..-1].each do |example|
127
+ examples.drop(1).each do |example|
127
128
  add_offense(example,
128
- location: :expression,
129
- message: message_for(example, examples[0]))
129
+ message: message_for(example, examples[0])) do |corrector|
130
+ clusters = example_clusters_for_autocorrect(example)
131
+ clusters.each do |metadata, examples|
132
+ range = range_for_replace(examples)
133
+ replacement = aggregated_example(examples, metadata)
134
+ corrector.replace(range, replacement)
135
+ examples.drop(1).map { |example| drop_example(corrector, example) }
136
+ end
137
+ end
130
138
  end
131
139
  end
132
140
  end
133
141
  end
134
142
 
135
- def autocorrect(example_node)
136
- clusters = example_clusters_for_autocorrect(example_node)
137
- return if clusters.empty?
138
-
139
- lambda do |corrector|
140
- clusters.each do |metadata, examples|
141
- range = range_for_replace(examples)
142
- replacement = aggregated_example(examples, metadata)
143
- corrector.replace(range, replacement)
144
- examples[1..-1].map { |example| drop_example(corrector, example) }
145
- end
146
- end
147
- end
148
-
149
143
  private
150
144
 
151
145
  # Clusters of examples in the same example group, on the same nesting
@@ -6,6 +6,29 @@ require "logger"
6
6
  require "test_prof/logging"
7
7
  require "test_prof/utils"
8
8
 
9
+ # Add an alias for Process.clock_gettime "reserved" for TestProf
10
+ # (in case some other tool would like to patch it)
11
+ module ::Process
12
+ class << self
13
+ # Already patched by Timecop
14
+ if method_defined?(:clock_gettime_without_mock)
15
+ alias_method :clock_gettime_for_test_prof, :clock_gettime_without_mock
16
+ else
17
+ alias_method :clock_gettime_for_test_prof, :clock_gettime
18
+
19
+ def singleton_method_added(method_name)
20
+ return super unless method_name == :clock_gettime_without_mock
21
+
22
+ define_method(:clock_gettime_for_test_prof) { |*args| clock_gettime_without_mock(*args) }
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # Main TestProf module
29
+ #
30
+ # Contains configuration and common methods
31
+
9
32
  # Ruby applications tests profiling tools.
10
33
  #
11
34
  # Contains tools to analyze factories usage, integrate with Ruby profilers,
@@ -52,9 +75,13 @@ module TestProf
52
75
  defined?(::Spring::Application) && (disabled.nil? || disabled.empty? || disabled == "0")
53
76
  end
54
77
 
78
+ def dry_run?
79
+ rspec? && ::RSpec.configuration.dry_run?
80
+ end
81
+
55
82
  # Returns the current process time
56
83
  def now
57
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
84
+ Process.clock_gettime_for_test_prof(Process::CLOCK_MONOTONIC)
58
85
  end
59
86
 
60
87
  # Require gem and shows a custom
@@ -48,16 +48,9 @@ module TestProf
48
48
 
49
49
  patch = Module.new do
50
50
  mids.each do |mid|
51
- if RUBY_VERSION >= "2.7.0"
52
- define_method(mid) do |*args, **kwargs, &block|
53
- next super(*args, **kwargs, &block) unless guard.nil? || instance_exec(*args, **kwargs, &guard)
54
- tracker.track { super(*args, **kwargs, &block) }
55
- end
56
- else
57
- define_method(mid) do |*args, &block|
58
- next super(*args, &block) unless guard.nil? || instance_exec(*args, &guard)
59
- tracker.track { super(*args, &block) }
60
- end
51
+ define_method(mid) do |*args, **kwargs, &block|
52
+ next super(*args, **kwargs, &block) unless guard.nil? || instance_exec(*args, **kwargs, &guard)
53
+ tracker.track { super(*args, **kwargs, &block) }
61
54
  end
62
55
  end
63
56
  end
@@ -12,7 +12,7 @@ module TestProf
12
12
  #
13
13
  # We need it to make sure that the state is clean.
14
14
  def refind
15
- self.class.find(send(self.class.primary_key))
15
+ self.class.unscoped.find(send(self.class.primary_key))
16
16
  end
17
17
  end
18
18
  end
@@ -12,7 +12,7 @@ module TestProf
12
12
  head = ((limit - 3) / 2)
13
13
  tail = head + 3 - limit
14
14
 
15
- "#{self[0..(head - 1)]}...#{self[tail..-1]}"
15
+ "#{self[0..(head - 1)]}...#{self[tail..]}"
16
16
  end
17
17
  end
18
18
  end