minitest-heat 0.0.5 → 0.0.6

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.
@@ -2,8 +2,8 @@
2
2
 
3
3
  require_relative 'output/backtrace'
4
4
  require_relative 'output/issue'
5
- require_relative 'output/location'
6
5
  require_relative 'output/map'
6
+ require_relative 'output/marker'
7
7
  require_relative 'output/results'
8
8
  require_relative 'output/source_code'
9
9
  require_relative 'output/token'
@@ -12,35 +12,6 @@ module Minitest
12
12
  module Heat
13
13
  # Friendly API for printing nicely-formatted output to the console
14
14
  class Output
15
- FORMATTERS = {
16
- error: [
17
- [ %i[error label], %i[muted spacer], %i[default test_name] ],
18
- [ %i[italicized summary], ],
19
- [ %i[default backtrace_summary] ],
20
- ],
21
- broken: [
22
- [ %i[broken label], %i[muted spacer], %i[default test_name], %i[muted spacer], %i[muted test_class] ],
23
- [ %i[italicized summary], ],
24
- [ %i[default backtrace_summary] ],
25
- ],
26
- failure: [
27
- [ %i[failure label], %i[muted spacer], %i[default test_name], %i[muted spacer], %i[muted test_class] ],
28
- [ %i[italicized summary] ],
29
- [ %i[muted short_location], ],
30
- [ %i[default source_summary], ],
31
- ],
32
- skipped: [
33
- [ %i[skipped label], %i[muted spacer], %i[default test_name], %i[muted spacer], %i[muted test_class] ],
34
- [ %i[italicized summary] ],
35
- [], # New Line
36
- ],
37
- slow: [
38
- [ %i[slow label], %i[muted spacer], %i[default test_name], %i[muted spacer], %i[default test_class] ],
39
- [ %i[bold slowness], %i[muted spacer], %i[default location], ],
40
- [], # New Line
41
- ]
42
- }
43
-
44
15
  attr_reader :stream
45
16
 
46
17
  def initialize(stream = $stdout)
@@ -59,106 +30,22 @@ module Minitest
59
30
  end
60
31
  alias newline puts
61
32
 
62
- # TOOD: Convert to output class
63
- # - This should likely live in the output/issue class
64
- # - Add a 'fail_fast' option that shows the issue as soon as the failure occurs
65
- def marker(value)
66
- case value
67
- when 'E' then text(:error, value)
68
- when 'B' then text(:failure, value)
69
- when 'F' then text(:failure, value)
70
- when 'S' then text(:skipped, value)
71
- else text(:success, value)
72
- end
73
- end
74
-
75
- # TOOD: Convert to output class
76
- # - This should likely live in the output/issue class
77
- # - There may be justification for creating different "strategies" for the various types
78
33
  def issue_details(issue)
79
- formatter = FORMATTERS[issue.type]
80
-
81
- formatter.each do |lines|
82
- lines.each do |tokens|
83
- style, content_method = *tokens
84
-
85
- if issue.respond_to?(content_method)
86
- # If it's an available method on issue, use that to get the content
87
- content = issue.send(content_method)
88
- text(style, content)
89
- else
90
- # Otherwise, fall back to output and pass issue to *it*
91
- send(content_method, issue)
92
- end
93
- end
94
- newline
95
- end
96
- end
97
-
98
- # TOOD: Convert to output class
99
- def heat_map(map)
100
- map.files.each do |file|
101
- pathname = Pathname(file[0])
102
-
103
- path = pathname.dirname.to_s
104
- filename = pathname.basename.to_s
105
-
106
- values = map.hits[pathname.to_s]
107
-
108
-
109
- text(:error, 'E' * values[:error].size) if values[:error]&.any?
110
- text(:broken, 'B' * values[:broken].size) if values[:broken]&.any?
111
- text(:failure, 'F' * values[:failure].size) if values[:failure]&.any?
112
-
113
- unless values[:error]&.any? || values[:broken]&.any? || values[:failure]&.any?
114
- text(:skipped, 'S' * values[:skipped].size) if values[:skipped]&.any?
115
- text(:painful, '—' * values[:painful].size) if values[:painful]&.any?
116
- text(:slow, '–' * values[:slow].size) if values[:slow]&.any?
117
- end
118
-
119
- text(:muted, ' ') if map.hits.any?
120
-
121
- text(:muted, "#{path.delete_prefix(Dir.pwd)}/")
122
- text(:default, filename)
123
-
124
- text(:muted, ':')
125
-
126
- all_line_numbers = values.fetch(:error, []) + values.fetch(:failure, [])
127
- all_line_numbers += values.fetch(:skipped, [])
128
-
129
- line_numbers = all_line_numbers.compact.uniq.sort
130
- line_numbers.each { |line_number| text(:muted, "#{line_number} ") }
131
- newline
132
- end
133
- newline
34
+ print_tokens Minitest::Heat::Output::Issue.new(issue).tokens
134
35
  end
135
36
 
136
- # TOOD: Convert to output class
137
- def test_name_summary(issue)
138
- text(:default, "#{issue.test_class} > #{issue.test_name}")
37
+ def marker(issue_type)
38
+ print_token Minitest::Heat::Output::Marker.new(issue_type).token
139
39
  end
140
40
 
141
41
  def compact_summary(results)
142
- results_tokens = ::Minitest::Heat::Output::Results.new(results).tokens
143
-
144
- newline
145
- print_tokens(results_tokens)
146
42
  newline
43
+ print_tokens ::Minitest::Heat::Output::Results.new(results).tokens
147
44
  end
148
45
 
149
- def backtrace_summary(issue)
150
- location = issue.location
151
-
152
- backtrace_tokens = ::Minitest::Heat::Output::Backtrace.new(location).tokens
153
- print_tokens(backtrace_tokens)
154
- end
155
-
156
- def source_summary(issue)
157
- filename = issue.location.project_file
158
- line_number = issue.location.project_failure_line
159
-
160
- source_code_tokens = ::Minitest::Heat::Output::SourceCode.new(filename, line_number).tokens
161
- print_tokens(source_code_tokens)
46
+ def heat_map(map)
47
+ newline
48
+ print_tokens ::Minitest::Heat::Output::Map.new(map).tokens
162
49
  end
163
50
 
164
51
  private
@@ -176,6 +63,10 @@ module Minitest
176
63
  style_enabled? ? :styled : :unstyled
177
64
  end
178
65
 
66
+ def print_token(token)
67
+ print Token.new(*token).to_s(token_format)
68
+ end
69
+
179
70
  def print_tokens(lines_of_tokens)
180
71
  lines_of_tokens.each do |tokens|
181
72
  tokens.each do |token|
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Minitest
4
4
  module Heat
5
+ # A collection of test failures
5
6
  class Results
6
-
7
7
  attr_reader :test_count,
8
8
  :assertion_count,
9
9
  :success_count,
@@ -20,6 +20,7 @@ module Minitest
20
20
  broken: [],
21
21
  failure: [],
22
22
  skipped: [],
23
+ painful: [],
23
24
  slow: []
24
25
  }
25
26
  @start_time = nil
@@ -69,12 +70,20 @@ module Minitest
69
70
  issues.fetch(:skipped) { [] }
70
71
  end
71
72
 
73
+ def painfuls
74
+ issues
75
+ .fetch(:painful) { [] }
76
+ .sort_by(&:time)
77
+ .reverse
78
+ .take(5)
79
+ end
80
+
72
81
  def slows
73
82
  issues
74
83
  .fetch(:slow) { [] }
75
- .sort { |issue| issue.time }
84
+ .sort_by(&:time)
76
85
  .reverse
77
- .take(3)
86
+ .take(5)
78
87
  end
79
88
 
80
89
  def errors?
@@ -93,6 +102,10 @@ module Minitest
93
102
  skips.any?
94
103
  end
95
104
 
105
+ def painfuls?
106
+ painfuls.any?
107
+ end
108
+
96
109
  def slows?
97
110
  slows.any?
98
111
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Minitest
2
4
  module Heat
3
- VERSION = "0.0.5"
5
+ VERSION = '0.0.6'
4
6
  end
5
7
  end
data/lib/minitest/heat.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'heat/backtrace'
4
+ require_relative 'heat/hit'
4
5
  require_relative 'heat/issue'
6
+ require_relative 'heat/line'
5
7
  require_relative 'heat/location'
6
8
  require_relative 'heat/map'
7
9
  require_relative 'heat/output'
@@ -3,12 +3,12 @@
3
3
  require_relative 'heat_reporter'
4
4
 
5
5
  module Minitest
6
- def self.plugin_heat_options(opts, options)
7
- opts.on '--show-fast', "Show failures as they happen instead of waiting for the entire suite." do
6
+ def self.plugin_heat_options(opts, _options)
7
+ opts.on '--show-fast', 'Show failures as they happen instead of waiting for the entire suite.' do
8
8
  # Heat.show_fast!
9
9
  end
10
10
 
11
- # TODO options.
11
+ # TODO: options.
12
12
  # 1. Fail Fast
13
13
  # 2. Don't worry about skips.
14
14
  # 3. Skip coverage.
@@ -18,9 +18,9 @@ module Minitest
18
18
  io = options[:io]
19
19
 
20
20
  # Clean out the existing reporters.
21
- self.reporter.reporters = []
21
+ reporter.reporters = []
22
22
 
23
23
  # Use Reviewer as the sole reporter.
24
- self.reporter << HeatReporter.new(io, options)
24
+ reporter << HeatReporter.new(io, options)
25
25
  end
26
26
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "heat"
3
+ require_relative 'heat'
4
4
 
5
5
  module Minitest
6
6
  # Custom minitest reporter to proactively identify likely culprits in test failures by focusing on
@@ -29,31 +29,31 @@ module Minitest
29
29
  # Pulls from minitest-color as well:
30
30
  # https://github.com/teoljungberg/minitest-color/blob/master/lib/minitest/color_plugin.rb
31
31
  class HeatReporter < AbstractReporter
32
-
33
32
  attr_reader :output,
34
33
  :options,
35
34
  :results,
36
35
  :map
37
36
 
38
37
  def initialize(io = $stdout, options = {})
39
- @output = Heat::Output.new(io)
40
38
  @options = options
41
39
 
42
- @results = Heat::Results.new
43
- @map = Heat::Map.new
40
+ @results = Heat::Results.new
41
+ @map = Heat::Map.new
42
+ @output = Heat::Output.new(io)
44
43
  end
45
44
 
46
45
  # Starts reporting on the run.
47
46
  def start
48
- output.puts
49
- output.puts
50
- @results.start_timer!
47
+ results.start_timer!
48
+
49
+ # A couple of blank lines to create some breathing room
50
+ output.newline
51
+ output.newline
51
52
  end
52
53
 
53
54
  # About to start running a test. This allows a reporter to show that it is starting or that we
54
55
  # are in the middle of a test run.
55
- def prerecord(klass, name)
56
- end
56
+ def prerecord(klass, name); end
57
57
 
58
58
  # Records the data from a result.
59
59
  # Minitest::Result source:
@@ -61,16 +61,17 @@ module Minitest
61
61
  def record(result)
62
62
  issue = Heat::Issue.new(result)
63
63
 
64
- @results.record(issue)
65
- @map.add(*issue.to_hit) if issue.hit?
64
+ results.record(issue)
65
+ map.add(*issue.to_hit) if issue.hit?
66
66
 
67
- output.marker(issue.marker)
67
+ output.marker(issue.type)
68
68
  end
69
69
 
70
70
  # Outputs the summary of the run.
71
71
  def report
72
- @results.stop_timer!
72
+ results.stop_timer!
73
73
 
74
+ # A couple of blank lines to create some breathing room
74
75
  output.newline
75
76
  output.newline
76
77
 
@@ -78,20 +79,20 @@ module Minitest
78
79
  # pressing issues are displayed at the bottom of the report in order to reduce scrolling.
79
80
  # This way, as you fix issues, the list gets shorter, and eventually the least critical
80
81
  # issues will be displayed without scrolling once more problematic issues are resolved.
81
- if results.failures.empty? && results.brokens.empty? && results.errors.empty? && results.skips.empty?
82
- results.slows.each { |issue| output.issue_details(issue) }
82
+ %i[slows painfuls skips failures brokens errors].each do |issue_category|
83
+ results.send(issue_category).each { |issue| output.issue_details(issue) }
83
84
  end
84
85
 
85
- if results.failures.empty? && results.brokens.empty? && results.errors.empty?
86
- results.skips.each { |issue| output.issue_details(issue) }
87
- end
88
-
89
- results.failures.each { |issue| output.issue_details(issue) }
90
- results.brokens.each { |issue| output.issue_details(issue) }
91
- results.errors.each { |issue| output.issue_details(issue) }
92
-
86
+ # Display a short summary of the total issue counts fore ach category as well as performance
87
+ # details for the test suite as a whole
93
88
  output.compact_summary(results)
89
+
90
+ # If there were issues, shows a short heat map summary of which files and lines were the most
91
+ # common sources of issues
94
92
  output.heat_map(map)
93
+
94
+ # A blank line to create some breathing room
95
+ output.newline
95
96
  end
96
97
 
97
98
  # Did this run pass?
@@ -21,8 +21,6 @@ Gem::Specification.new do |spec|
21
21
  spec.metadata['source_code_uri'] = 'https://github.com/garrettdimon/minitest-heat'
22
22
  spec.metadata['wiki_uri'] = 'https://github.com/garrettdimon/minitest-heat/wiki'
23
23
 
24
-
25
-
26
24
  # Specify which files should be added to the gem when it is released.
27
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
@@ -34,7 +32,11 @@ Gem::Specification.new do |spec|
34
32
 
35
33
  spec.add_runtime_dependency 'minitest'
36
34
 
35
+ spec.add_development_dependency 'awesome_print'
37
36
  spec.add_development_dependency 'dead_end'
38
37
  spec.add_development_dependency 'pry'
38
+ spec.add_development_dependency 'rubocop'
39
+ spec.add_development_dependency 'rubocop-minitest'
40
+ spec.add_development_dependency 'rubocop-rake'
39
41
  spec.add_development_dependency 'simplecov'
40
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-heat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garrett Dimon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-13 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: awesome_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: dead_end
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,48 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
55
111
  - !ruby/object:Gem::Dependency
56
112
  name: simplecov
57
113
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +131,7 @@ extensions: []
75
131
  extra_rdoc_files: []
76
132
  files:
77
133
  - ".gitignore"
134
+ - ".rubocop.yml"
78
135
  - ".travis.yml"
79
136
  - CODE_OF_CONDUCT.md
80
137
  - Gemfile
@@ -86,14 +143,16 @@ files:
86
143
  - bin/setup
87
144
  - lib/minitest/heat.rb
88
145
  - lib/minitest/heat/backtrace.rb
146
+ - lib/minitest/heat/hit.rb
89
147
  - lib/minitest/heat/issue.rb
148
+ - lib/minitest/heat/line.rb
90
149
  - lib/minitest/heat/location.rb
91
150
  - lib/minitest/heat/map.rb
92
151
  - lib/minitest/heat/output.rb
93
152
  - lib/minitest/heat/output/backtrace.rb
94
153
  - lib/minitest/heat/output/issue.rb
95
- - lib/minitest/heat/output/location.rb
96
154
  - lib/minitest/heat/output/map.rb
155
+ - lib/minitest/heat/output/marker.rb
97
156
  - lib/minitest/heat/output/results.rb
98
157
  - lib/minitest/heat/output/source_code.rb
99
158
  - lib/minitest/heat/output/token.rb
@@ -128,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
187
  - !ruby/object:Gem::Version
129
188
  version: '0'
130
189
  requirements: []
131
- rubygems_version: 3.1.4
190
+ rubygems_version: 3.1.6
132
191
  signing_key:
133
192
  specification_version: 4
134
193
  summary: Presents test results in a visual manner to guide you to where to look first.
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Minitest
4
- module Heat
5
- class Output
6
- class Location
7
- attr_accessor :location
8
-
9
- def initialize(location)
10
- @location = location
11
- end
12
-
13
- def tokens
14
- end
15
-
16
- private
17
- end
18
- end
19
- end
20
- end