Class: Blame

Inherits:
RSpec::Core::Formatters::ProgressFormatter
  • Object
show all
Defined in:
lib/rspec/blame.rb

Overview

Formatter that ouputs git blame details for the slowest examples.

Instance Method Summary collapse

Instance Method Details

#_example_run_timeObject



110
111
112
# File 'lib/rspec/blame.rb', line 110

def _example_run_time
  lambda { |example| example.execution_result[:run_time] }
end

#_format_seconds(float) ⇒ Object



122
123
124
# File 'lib/rspec/blame.rb', line 122

def _format_seconds(float)
  formatted = "%.#{float >= 1 ? 2 : 4}f" % float
end

#_number_of_examples_to_profileObject



114
115
116
# File 'lib/rspec/blame.rb', line 114

def _number_of_examples_to_profile
  RSpec.configuration.profile_examples
end

#_print_example_details(example) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rspec/blame.rb', line 48

def _print_example_details(example)
  output.puts "  #{example.full_description}"
  output.print "#{color("    #{_format_seconds(_example_run_time.call(example))} secs".ljust(19, ' '), :red)}" + " #{color(example.location.ljust(79, ' '), :yellow)}"

  file, line_number = example.location.split(":")
  git_blame_output = %x(git blame -c --date=short -L #{line_number},#{line_number} #{file})
  blame = /(?<commit>\S+)\s*\((?<author>\D+)(?<date>\S+)/.match(git_blame_output)

  if blame.nil?
    output.puts
  else
    commit_details = " Author: #{blame[:author].strip}, Date: #{blame[:date]}, Hash: #{blame[:commit]}"
    output.puts(color(commit_details.ljust(60, ' '), :cyan))
  end
end

#_print_example_group_details(location, details) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'lib/rspec/blame.rb', line 100

def _print_example_group_details(location, details)
  output.puts "  #{details[:description]}"

  average = color("#{_format_seconds(details[:average])} secs avg".ljust(15, " "), :red)
  total   = "#{_format_seconds(details[:total_time])} secs"
  count   = "#{details[:count]}"
  calc    = color(" Execution Time: #{total}, Examples: #{count}".ljust(60, " "), :cyan)
  output.puts "    #{average}" + " #{color(location.split(":")[0].ljust(79, ' '), :yellow)}" + calc
end

#_print_example_group_summary(slowest_example_groups) ⇒ Object



96
97
98
# File 'lib/rspec/blame.rb', line 96

def _print_example_group_summary(slowest_example_groups)
  output.puts "\nSlowest #{pluralize(slowest_example_groups.size, "example group")}:"
end

#_print_example_summary(slowest_examples) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rspec/blame.rb', line 36

def _print_example_summary(slowest_examples)
  slowest_tests_time   = _total_time(slowest_examples)
  total_time           = _total_time(examples)
  formatted_percentage = '%.1f' % (slowest_tests_time / total_time * 100)

  number_of_test     = "\nSlowest #{pluralize(slowest_examples.size, "example")} "
  slowest_total_time = "finished in #{_format_seconds(slowest_tests_time)} secs "
  percent_and_total  = "(#{formatted_percentage}% of total time: #{_format_seconds(total_time)} secs).\n"

  output.puts number_of_test +  slowest_total_time + percent_and_total
end

#_print_profile_thresholdObject



15
16
17
# File 'lib/rspec/blame.rb', line 15

def _print_profile_threshold
  output.puts "\nPrinting examples and example groups exceeding the profile threshold (#{_format_seconds(_profile_threshold)} secs):"
end

#_profile_thresholdObject



118
119
120
# File 'lib/rspec/blame.rb', line 118

def _profile_threshold
  RSpec.configuration.profile_threshold
end

#_slowest_example_groups(examples) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rspec/blame.rb', line 80

def _slowest_example_groups(examples)
  slowest_example_groups = {}
  examples.each do |example|
    location = example.example_group.parent_groups.last.[:example_group][:location]
    slowest_example_groups[location] ||= Hash.new(0)
    slowest_example_groups[location][:total_time]  += example.execution_result[:run_time]
    slowest_example_groups[location][:count]       += 1
    slowest_example_groups[location][:description] = example.example_group.top_level_description unless slowest_example_groups[location].has_key?(:description)
  end
  slowest_example_groups.each { |location, details| details[:average] = details[:total_time].to_f / details[:count] }

  sorted_example_groups = slowest_example_groups.sort_by { |location, details| details[:average] }.reverse.first(_number_of_examples_to_profile)

  _profile_threshold ? sorted_example_groups.select { |location, details| details[:average] > _profile_threshold } : sorted_example_groups
end

#_slowest_examples(examples) ⇒ Object



31
32
33
34
# File 'lib/rspec/blame.rb', line 31

def _slowest_examples(examples)
  slowest_examples = examples.sort_by(&_example_run_time).reverse.first(_number_of_examples_to_profile)
  _profile_threshold ? slowest_examples.select { |example| _example_run_time.call(example) > _profile_threshold } : slowest_examples
end

#_total_time(examples) ⇒ Object



64
65
66
# File 'lib/rspec/blame.rb', line 64

def _total_time(examples)
  examples.map(&_example_run_time).inject { |sum, time| sum + time }
end

#dump_profileObject

Prints out profile results and profile threshold if set in RSpec.configuration.



7
8
9
10
11
12
13
# File 'lib/rspec/blame.rb', line 7

def dump_profile
  start = Time.now
  _print_profile_threshold unless _profile_threshold.nil?
  dump_profile_slowest_examples
  dump_profile_slowest_example_groups
  output.puts "\nProfiling finished in #{_format_seconds(Time.now - start)} secs."
end

#dump_profile_slowest_example_groupsObject

Prints example group profiling result.



69
70
71
72
73
74
75
76
77
78
# File 'lib/rspec/blame.rb', line 69

def dump_profile_slowest_example_groups
  slowest_example_groups = _slowest_example_groups(examples)

  return output.puts color("\nAll example groups are faster than #{_format_seconds(_profile_threshold)} secs.", :green) if _profile_threshold && slowest_example_groups.empty?

  _print_example_group_summary(slowest_example_groups)
  slowest_example_groups.each do |location, details|
    _print_example_group_details(location, details)
  end
end

#dump_profile_slowest_examplesObject

Appends to ProgressFormatter’s output by executing git blame in a subprocess and parsing its output.



20
21
22
23
24
25
26
27
28
29
# File 'lib/rspec/blame.rb', line 20

def dump_profile_slowest_examples
  slowest_examples = _slowest_examples(examples)

  return output.puts color("\nAll examples are faster than #{_format_seconds(_profile_threshold)} secs.", :green) if _profile_threshold && slowest_examples.empty?

  _print_example_summary(slowest_examples)
  slowest_examples.each do |example|
    _print_example_details(example)
  end
end