Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit bc11555

Browse files
committed
Fix group profile output regressions introduced in #1971.
Regressions fixed by this commit: - We only considered top-level groups before, but #1971 made it consider nested groups as well. However, the example count was only incremented on the top-level group, which meant the output said “Inf seconds” since `float / 0` returns `Infinity`. - We were wrongly listing the example group class name rather than the location. This is because we changed from locations to groups in the hash. Fixes #1989.
1 parent a05496b commit bc11555

File tree

7 files changed

+69
-14
lines changed

7 files changed

+69
-14
lines changed

features/configuration/profile.feature

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ Feature: Profile examples
226226
before(:context) do
227227
sleep 0.2
228228
end
229-
it "example" do
230-
expect(10).to eq(10)
229+
230+
context "nested" do
231+
it "example" do
232+
expect(10).to eq(10)
233+
end
231234
end
232235
end
233236
@@ -239,4 +242,4 @@ Feature: Profile examples
239242
end
240243
"""
241244
When I run `rspec spec --profile 1`
242-
Then the output should contain "slow before context hook"
245+
Then the output should report "slow before context hook" as the slowest example group

features/step_definitions/additional_cli_steps.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,30 @@
197197
expect(normalize_failure_output(all_output)).to include(normalize_failure_output(string))
198198
end
199199

200+
Then(/^the output should report "slow before context hook" as the slowest example group$/) do
201+
# These expectations are trying to guard against a regression that introduced
202+
# this output:
203+
# Top 1 slowest example groups:
204+
# slow before context hook
205+
# Inf seconds average (0.00221 seconds / 0 examples) RSpec::ExampleGroups::SlowBeforeContextHook::Nested
206+
#
207+
# Problems:
208+
# - "Inf seconds"
209+
# - 0 examples
210+
# - "Nested" group listed (it should be the outer group)
211+
# - The example group class name is listed (it should be the location)
212+
213+
expect(all_output).not_to match(/nested/i)
214+
expect(all_output).not_to match(/inf/i)
215+
expect(all_output).not_to match(/\b0 examples/i)
216+
217+
seconds = '\d+(?:\.\d+)? seconds'
218+
219+
expect(all_output).to match(
220+
%r{Top 1 slowest example groups?:\n\s+slow before context hook\n\s+#{seconds} average \(#{seconds} / 1 example\) \./spec/example_spec\.rb:1}
221+
)
222+
end
223+
200224
module Normalization
201225
def normalize_failure_output(text)
202226
whitespace_normalized = text.lines.map { |line| line.sub(/\s+$/, '').sub(/:in .*$/, '') }.join

lib/rspec/core/example_group.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ def self.parent_groups
436436
@parent_groups ||= ancestors.select { |a| a < RSpec::Core::ExampleGroup }
437437
end
438438

439+
# @private
440+
def self.top_level?
441+
superclass == ExampleGroup
442+
end
443+
439444
# @private
440445
def self.ensure_example_groups_are_configured
441446
unless defined?(@@example_groups_configured)

lib/rspec/core/notifications.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,8 @@ def calculate_slowest_groups
450450
hash[:average] = hash[:total_time].to_f / hash[:count]
451451
end
452452

453-
@example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
453+
groups = @example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
454+
groups.map { |group, data| [group.location, data] }
454455
end
455456
end
456457

lib/rspec/core/profiler.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ def initialize
1111
attr_reader :example_groups
1212

1313
def example_group_started(notification)
14+
return unless notification.group.top_level?
15+
1416
@example_groups[notification.group][:start] = Time.now
1517
@example_groups[notification.group][:description] = notification.group.top_level_description
1618
end
1719

1820
def example_group_finished(notification)
21+
return unless notification.group.top_level?
22+
1923
@example_groups[notification.group][:total_time] = Time.now - @example_groups[notification.group][:start]
2024
end
2125

spec/rspec/core/formatters/profile_formatter_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def profile *groups
5757
before do
5858
example_clock = class_double(RSpec::Core::Time, :now => RSpec::Core::Time.now + 0.5)
5959

60+
@slow_group_line_number = __LINE__ + 1
6061
group1 = RSpec.describe("slow group") do
6162
example("example") do |example|
6263
# make it look slow without actually taking up precious time
@@ -84,6 +85,10 @@ def profile *groups
8485
it "ranks the example groups by average time" do
8586
expect(formatter_output.string).to match(/slow group(.*)fast group/m)
8687
end
88+
89+
it "prints the location of the slow groups" do
90+
expect(formatter_output.string).to include("#{RSpec::Core::Metadata.relative_path __FILE__}:#{@slow_group_line_number}")
91+
end
8792
end
8893
end
8994
end

spec/rspec/core/profiler_spec.rb

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,26 @@
1717
allow(::RSpec::Core::Time).to receive(:now) { now }
1818
end
1919

20-
def group
21-
@group ||=
22-
begin
23-
group = super
24-
allow(group).to receive(:top_level_description) { description }
25-
group
26-
end
27-
end
20+
let(:group) { RSpec.describe "My Group" }
2821

2922
describe '#example_group_started' do
30-
it 'records example groups start time and description via id' do
23+
it 'records example groups start time and description' do
3124
expect {
3225
profiler.example_group_started group_notification group
3326
}.to change { profiler.example_groups[group] }.
3427
from(a_hash_excluding(:start, :description)).
3528
to(a_hash_including(:start => now, :description => description))
3629
end
30+
31+
context "when the group is not a top-level group" do
32+
let(:group) { super().describe "nested" }
33+
34+
it 'no-ops since we only consider top-level groups for profiling' do
35+
expect {
36+
profiler.example_group_started group_notification group
37+
}.not_to change(profiler, :example_groups)
38+
end
39+
end
3740
end
3841

3942
describe '#example_group_finished' do
@@ -42,13 +45,23 @@ def group
4245
allow(::RSpec::Core::Time).to receive(:now) { now + 1 }
4346
end
4447

45-
it 'records example groups total time and description via id' do
48+
it 'records example groups total time and description' do
4649
expect {
4750
profiler.example_group_finished group_notification group
4851
}.to change { profiler.example_groups[group] }.
4952
from(a_hash_excluding(:total_time)).
5053
to(a_hash_including(:total_time => 1.0))
5154
end
55+
56+
context "when the group is not a top-level group" do
57+
let(:group) { super().describe "nested" }
58+
59+
it 'no-ops since we only consider top-level groups for profiling' do
60+
expect {
61+
profiler.example_group_finished group_notification group
62+
}.not_to change(profiler, :example_groups)
63+
end
64+
end
5265
end
5366

5467
describe '#example_started' do

0 commit comments

Comments
 (0)