minitest-heat 1.1.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +79 -8
- data/.github/workflows/release.yml +98 -0
- data/.rubocop.yml +7 -2
- data/CHANGELOG.md +35 -1
- data/Gemfile +5 -1
- data/Gemfile.lock +77 -37
- data/README.md +91 -9
- data/RELEASING.md +191 -0
- data/Rakefile +117 -0
- data/lib/minitest/heat/backtrace/line_count.rb +38 -0
- data/lib/minitest/heat/backtrace/line_parser.rb +4 -2
- data/lib/minitest/heat/backtrace.rb +2 -1
- data/lib/minitest/heat/configuration.rb +7 -2
- data/lib/minitest/heat/hit.rb +30 -14
- data/lib/minitest/heat/issue.rb +43 -9
- data/lib/minitest/heat/location.rb +24 -2
- data/lib/minitest/heat/map.rb +7 -0
- data/lib/minitest/heat/output/backtrace.rb +5 -5
- data/lib/minitest/heat/output/issue.rb +12 -5
- data/lib/minitest/heat/output/results.rb +6 -1
- data/lib/minitest/heat/output/token.rb +2 -2
- data/lib/minitest/heat/output.rb +3 -2
- data/lib/minitest/heat/results.rb +41 -8
- data/lib/minitest/heat/source.rb +4 -3
- data/lib/minitest/heat/timer.rb +13 -0
- data/lib/minitest/heat/version.rb +1 -1
- data/lib/minitest/heat_plugin.rb +6 -0
- data/lib/minitest/heat_reporter.rb +44 -8
- data/minitest-heat.gemspec +4 -3
- metadata +14 -14
- data/.travis.yml +0 -6
|
@@ -69,7 +69,9 @@ module Minitest
|
|
|
69
69
|
# @return [String] the cleaned up version of the test name
|
|
70
70
|
def test_name(issue)
|
|
71
71
|
test_prefix = 'test_'
|
|
72
|
-
identifier = issue.test_identifier
|
|
72
|
+
identifier = issue.test_identifier.to_s
|
|
73
|
+
|
|
74
|
+
return 'Unknown test' if identifier.empty?
|
|
73
75
|
|
|
74
76
|
if identifier.start_with?(test_prefix)
|
|
75
77
|
identifier.delete_prefix(test_prefix).gsub('_', ' ').capitalize
|
|
@@ -87,22 +89,24 @@ module Minitest
|
|
|
87
89
|
end
|
|
88
90
|
|
|
89
91
|
def test_location_tokens
|
|
92
|
+
source_line = locations.test_failure.source_code.line
|
|
90
93
|
[
|
|
91
94
|
[:default, locations.test_definition.relative_filename],
|
|
92
95
|
[:muted, ':'],
|
|
93
96
|
[:default, locations.test_definition.line_number],
|
|
94
97
|
arrow_token,
|
|
95
98
|
[:default, locations.test_failure.line_number],
|
|
96
|
-
[:muted, "\n #{
|
|
99
|
+
[:muted, "\n #{source_line&.strip || '(source unavailable)'}"]
|
|
97
100
|
]
|
|
98
101
|
end
|
|
99
102
|
|
|
100
103
|
def location_tokens
|
|
104
|
+
source_line = locations.most_relevant.source_code.line
|
|
101
105
|
[
|
|
102
106
|
[:default, locations.most_relevant.relative_filename],
|
|
103
107
|
[:muted, ':'],
|
|
104
108
|
[:default, locations.most_relevant.line_number],
|
|
105
|
-
[:muted, "\n #{
|
|
109
|
+
[:muted, "\n #{source_line&.strip || '(source unavailable)'}"]
|
|
106
110
|
]
|
|
107
111
|
end
|
|
108
112
|
|
|
@@ -110,12 +114,15 @@ module Minitest
|
|
|
110
114
|
filename = locations.project.filename
|
|
111
115
|
line_number = locations.project.line_number
|
|
112
116
|
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
|
117
|
+
source_line = source.line
|
|
113
118
|
|
|
114
|
-
[[:muted, " #{Output::SYMBOLS[:arrow]} `#{source
|
|
119
|
+
[[:muted, " #{Output::SYMBOLS[:arrow]} `#{source_line&.strip || '(source unavailable)'}`"]]
|
|
115
120
|
end
|
|
116
121
|
|
|
117
122
|
def summary_tokens
|
|
118
|
-
|
|
123
|
+
summary_text = issue.summary.to_s
|
|
124
|
+
cleaned = summary_text.delete_suffix('---------------').strip
|
|
125
|
+
[[:italicized, cleaned.empty? ? '(no details available)' : cleaned]]
|
|
119
126
|
end
|
|
120
127
|
|
|
121
128
|
def slowness_summary_tokens
|
|
@@ -9,7 +9,12 @@ module Minitest
|
|
|
9
9
|
|
|
10
10
|
attr_accessor :results, :timer
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Explicitly define issues to avoid Forwardable warning about Object#issues private method
|
|
13
|
+
def issues
|
|
14
|
+
@results.issues
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def_delegators :@results, :errors, :brokens, :failures, :skips, :painfuls, :slows, :problems?
|
|
13
18
|
|
|
14
19
|
def initialize(results, timer)
|
|
15
20
|
@results = results
|
|
@@ -17,10 +17,10 @@ module Minitest
|
|
|
17
17
|
failure: %i[default red],
|
|
18
18
|
skipped: %i[default yellow],
|
|
19
19
|
warning_light: %i[light yellow],
|
|
20
|
-
italicized: %i[italic
|
|
20
|
+
italicized: %i[italic default],
|
|
21
21
|
bold: %i[bold default],
|
|
22
22
|
default: %i[default default],
|
|
23
|
-
muted: %i[light
|
|
23
|
+
muted: %i[light default]
|
|
24
24
|
}.freeze
|
|
25
25
|
|
|
26
26
|
attr_accessor :style_key, :content
|
data/lib/minitest/heat/output.rb
CHANGED
|
@@ -154,8 +154,9 @@ module Minitest
|
|
|
154
154
|
tokens.each do |token|
|
|
155
155
|
begin
|
|
156
156
|
print Token.new(*token).to_s(token_format)
|
|
157
|
-
rescue
|
|
158
|
-
|
|
157
|
+
rescue ArgumentError => e
|
|
158
|
+
# Token format error - output debug info and continue
|
|
159
|
+
puts "Token error (#{e.message}): #{token.inspect}"
|
|
159
160
|
end
|
|
160
161
|
end
|
|
161
162
|
newline
|
|
@@ -35,15 +35,15 @@ module Minitest
|
|
|
35
35
|
# numbers if the tests reference a shared method with an assertion in it. So in those cases,
|
|
36
36
|
# the backtrace is simply the test definition
|
|
37
37
|
backtrace = if issue.error?
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
# With errors, we have a backtrace
|
|
39
|
+
issue.locations.backtrace.project_locations
|
|
40
|
+
else
|
|
41
|
+
# With failures, the test definition is the most granular backtrace equivalent
|
|
42
|
+
location = issue.locations.test_definition
|
|
43
|
+
location.raw_container = issue.test_identifier
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
[location]
|
|
46
|
+
end
|
|
47
47
|
|
|
48
48
|
@heat_map.add(pathname, line_number, issue.type, backtrace: backtrace)
|
|
49
49
|
end
|
|
@@ -76,6 +76,39 @@ module Minitest
|
|
|
76
76
|
@slows ||= select_issues(:slow).sort_by(&:execution_time).reverse
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
# Returns count statistics by issue type
|
|
80
|
+
#
|
|
81
|
+
# @return [Hash] counts for each issue type
|
|
82
|
+
def statistics
|
|
83
|
+
{
|
|
84
|
+
total: issues.size,
|
|
85
|
+
errors: errors.size,
|
|
86
|
+
broken: brokens.size,
|
|
87
|
+
failures: failures.size,
|
|
88
|
+
skipped: skips.size,
|
|
89
|
+
painful: painfuls.size,
|
|
90
|
+
slow: slows.size
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns all issues that are not successes
|
|
95
|
+
#
|
|
96
|
+
# @return [Array<Issue>] issues that represent problems (errors, failures, skips, slow)
|
|
97
|
+
def issues_with_problems
|
|
98
|
+
issues.select(&:hit?)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Generates a hash representation for JSON serialization
|
|
102
|
+
#
|
|
103
|
+
# @return [Hash] results data
|
|
104
|
+
def to_h
|
|
105
|
+
{
|
|
106
|
+
statistics: statistics,
|
|
107
|
+
heat_map: heat_map.to_h,
|
|
108
|
+
issues: issues_with_problems.map(&:to_h)
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
|
|
79
112
|
private
|
|
80
113
|
|
|
81
114
|
def select_issues(issue_type)
|
data/lib/minitest/heat/source.rb
CHANGED
|
@@ -52,13 +52,14 @@ module Minitest
|
|
|
52
52
|
# @return [type] [description]
|
|
53
53
|
def file_lines
|
|
54
54
|
@raw_lines ||= File.readlines(filename, chomp: true)
|
|
55
|
-
|
|
55
|
+
# Remove trailing empty lines, checking for nil/empty safely
|
|
56
|
+
@raw_lines.pop while @raw_lines.any? && @raw_lines.last&.strip.to_s.empty?
|
|
56
57
|
|
|
57
58
|
@raw_lines
|
|
58
|
-
rescue Errno::ENOENT
|
|
59
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR, IOError, Encoding::UndefinedConversionError
|
|
59
60
|
# Occasionally, for a variety of reasons, a file can't be read. In those cases, it's best to
|
|
60
61
|
# return no source code lines rather than have the test suite raise an error unrelated to
|
|
61
|
-
# the code being tested
|
|
62
|
+
# the code being tested because that gets confusing.
|
|
62
63
|
[]
|
|
63
64
|
end
|
|
64
65
|
|
data/lib/minitest/heat/timer.rb
CHANGED
|
@@ -66,6 +66,19 @@ module Minitest
|
|
|
66
66
|
(assertion_count / total_time).round(2)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Generates a hash representation for JSON serialization
|
|
70
|
+
#
|
|
71
|
+
# @return [Hash] timing data
|
|
72
|
+
def to_h
|
|
73
|
+
{
|
|
74
|
+
total_seconds: total_time,
|
|
75
|
+
test_count: test_count,
|
|
76
|
+
assertion_count: assertion_count,
|
|
77
|
+
tests_per_second: tests_per_second,
|
|
78
|
+
assertions_per_second: assertions_per_second
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
|
|
69
82
|
private
|
|
70
83
|
|
|
71
84
|
# The total time the test suite was running.
|
data/lib/minitest/heat_plugin.rb
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
require_relative 'heat_reporter'
|
|
4
4
|
|
|
5
5
|
module Minitest # rubocop:disable Style/Documentation
|
|
6
|
+
def self.plugin_heat_options(opts, options)
|
|
7
|
+
opts.on '--heat-json', 'Output results as JSON instead of human-readable format' do
|
|
8
|
+
options[:heat_json] = true
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
6
12
|
def self.plugin_heat_init(options)
|
|
7
13
|
io = options.fetch(:io, $stdout)
|
|
8
14
|
|
|
@@ -48,7 +48,9 @@ module Minitest
|
|
|
48
48
|
def start
|
|
49
49
|
timer.start!
|
|
50
50
|
|
|
51
|
-
# A couple of blank lines to create some breathing room
|
|
51
|
+
# A couple of blank lines to create some breathing room (skip for JSON output)
|
|
52
|
+
return if json_output?
|
|
53
|
+
|
|
52
54
|
output.newline
|
|
53
55
|
output.newline
|
|
54
56
|
end
|
|
@@ -72,8 +74,8 @@ module Minitest
|
|
|
72
74
|
# Record the issue to show details later
|
|
73
75
|
results.record(issue)
|
|
74
76
|
|
|
75
|
-
# Show the marker
|
|
76
|
-
output.marker(issue.type)
|
|
77
|
+
# Show the marker (skip for JSON output)
|
|
78
|
+
output.marker(issue.type) unless json_output?
|
|
77
79
|
rescue StandardError => e
|
|
78
80
|
display_exception_guidance(e)
|
|
79
81
|
end
|
|
@@ -93,6 +95,45 @@ module Minitest
|
|
|
93
95
|
def report
|
|
94
96
|
timer.stop!
|
|
95
97
|
|
|
98
|
+
if json_output?
|
|
99
|
+
output_json
|
|
100
|
+
else
|
|
101
|
+
output_text
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Whether to output JSON instead of human-readable text
|
|
106
|
+
#
|
|
107
|
+
# @return [Boolean] true if --heat-json flag was passed
|
|
108
|
+
def json_output?
|
|
109
|
+
options[:heat_json]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Did this run pass?
|
|
113
|
+
def passed?
|
|
114
|
+
results.errors.empty? && results.failures.empty?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def output_json
|
|
120
|
+
require 'json'
|
|
121
|
+
output.stream.puts JSON.pretty_generate(json_results)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def json_results
|
|
125
|
+
{
|
|
126
|
+
version: '1.0',
|
|
127
|
+
status: results.problems? ? 'failed' : 'passed',
|
|
128
|
+
timestamp: Time.now.iso8601,
|
|
129
|
+
statistics: results.statistics,
|
|
130
|
+
timing: timer.to_h,
|
|
131
|
+
heat_map: results.heat_map.to_h,
|
|
132
|
+
issues: results.issues_with_problems.map(&:to_h)
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def output_text
|
|
96
137
|
# The list of individual issues and their associated details
|
|
97
138
|
output.issues_list(results)
|
|
98
139
|
|
|
@@ -107,10 +148,5 @@ module Minitest
|
|
|
107
148
|
output.newline
|
|
108
149
|
output.newline
|
|
109
150
|
end
|
|
110
|
-
|
|
111
|
-
# Did this run pass?
|
|
112
|
-
def passed?
|
|
113
|
-
results.errors.empty? && results.failures.empty?
|
|
114
|
-
end
|
|
115
151
|
end
|
|
116
152
|
end
|
data/minitest-heat.gemspec
CHANGED
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.description = 'Presents test results in a visual manner to guide you to where to look first.'
|
|
13
13
|
spec.homepage = 'https://github.com/garrettdimon/minitest-heat'
|
|
14
14
|
spec.license = 'MIT'
|
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new('>=
|
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.1')
|
|
16
16
|
|
|
17
17
|
spec.metadata['homepage_uri'] = spec.homepage
|
|
18
18
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/garrettdimon/minitest-heat/issues'
|
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/minitest-heat'
|
|
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
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
23
24
|
|
|
24
25
|
# Specify which files should be added to the gem when it is released.
|
|
25
26
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
@@ -33,10 +34,10 @@ Gem::Specification.new do |spec|
|
|
|
33
34
|
spec.add_runtime_dependency 'minitest'
|
|
34
35
|
|
|
35
36
|
spec.add_development_dependency 'awesome_print'
|
|
36
|
-
spec.add_development_dependency '
|
|
37
|
-
spec.add_development_dependency 'pry'
|
|
37
|
+
spec.add_development_dependency 'debug'
|
|
38
38
|
spec.add_development_dependency 'rubocop'
|
|
39
39
|
spec.add_development_dependency 'rubocop-minitest'
|
|
40
40
|
spec.add_development_dependency 'rubocop-rake'
|
|
41
41
|
spec.add_development_dependency 'simplecov'
|
|
42
|
+
spec.add_development_dependency 'simplecov_json_formatter'
|
|
42
43
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minitest-heat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Garrett Dimon
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: minitest
|
|
@@ -39,7 +38,7 @@ dependencies:
|
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: '0'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
41
|
+
name: debug
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - ">="
|
|
@@ -53,7 +52,7 @@ dependencies:
|
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '0'
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
55
|
+
name: rubocop
|
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
|
58
57
|
requirements:
|
|
59
58
|
- - ">="
|
|
@@ -67,7 +66,7 @@ dependencies:
|
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '0'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: rubocop
|
|
69
|
+
name: rubocop-minitest
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
72
71
|
requirements:
|
|
73
72
|
- - ">="
|
|
@@ -81,7 +80,7 @@ dependencies:
|
|
|
81
80
|
- !ruby/object:Gem::Version
|
|
82
81
|
version: '0'
|
|
83
82
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rubocop-
|
|
83
|
+
name: rubocop-rake
|
|
85
84
|
requirement: !ruby/object:Gem::Requirement
|
|
86
85
|
requirements:
|
|
87
86
|
- - ">="
|
|
@@ -95,7 +94,7 @@ dependencies:
|
|
|
95
94
|
- !ruby/object:Gem::Version
|
|
96
95
|
version: '0'
|
|
97
96
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
97
|
+
name: simplecov
|
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
|
100
99
|
requirements:
|
|
101
100
|
- - ">="
|
|
@@ -109,7 +108,7 @@ dependencies:
|
|
|
109
108
|
- !ruby/object:Gem::Version
|
|
110
109
|
version: '0'
|
|
111
110
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
111
|
+
name: simplecov_json_formatter
|
|
113
112
|
requirement: !ruby/object:Gem::Requirement
|
|
114
113
|
requirements:
|
|
115
114
|
- - ">="
|
|
@@ -132,20 +131,22 @@ extra_rdoc_files: []
|
|
|
132
131
|
files:
|
|
133
132
|
- ".github/FUNDING.yml"
|
|
134
133
|
- ".github/workflows/main.yml"
|
|
134
|
+
- ".github/workflows/release.yml"
|
|
135
135
|
- ".gitignore"
|
|
136
136
|
- ".rubocop.yml"
|
|
137
|
-
- ".travis.yml"
|
|
138
137
|
- CHANGELOG.md
|
|
139
138
|
- CODE_OF_CONDUCT.md
|
|
140
139
|
- Gemfile
|
|
141
140
|
- Gemfile.lock
|
|
142
141
|
- LICENSE.txt
|
|
143
142
|
- README.md
|
|
143
|
+
- RELEASING.md
|
|
144
144
|
- Rakefile
|
|
145
145
|
- bin/console
|
|
146
146
|
- bin/setup
|
|
147
147
|
- lib/minitest/heat.rb
|
|
148
148
|
- lib/minitest/heat/backtrace.rb
|
|
149
|
+
- lib/minitest/heat/backtrace/line_count.rb
|
|
149
150
|
- lib/minitest/heat/backtrace/line_parser.rb
|
|
150
151
|
- lib/minitest/heat/configuration.rb
|
|
151
152
|
- lib/minitest/heat/hit.rb
|
|
@@ -178,7 +179,7 @@ metadata:
|
|
|
178
179
|
documentation_uri: https://www.rubydoc.info/gems/minitest-heat
|
|
179
180
|
source_code_uri: https://github.com/garrettdimon/minitest-heat
|
|
180
181
|
wiki_uri: https://github.com/garrettdimon/minitest-heat/wiki
|
|
181
|
-
|
|
182
|
+
rubygems_mfa_required: 'true'
|
|
182
183
|
rdoc_options: []
|
|
183
184
|
require_paths:
|
|
184
185
|
- lib
|
|
@@ -186,15 +187,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
186
187
|
requirements:
|
|
187
188
|
- - ">="
|
|
188
189
|
- !ruby/object:Gem::Version
|
|
189
|
-
version:
|
|
190
|
+
version: '3.1'
|
|
190
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
192
|
requirements:
|
|
192
193
|
- - ">="
|
|
193
194
|
- !ruby/object:Gem::Version
|
|
194
195
|
version: '0'
|
|
195
196
|
requirements: []
|
|
196
|
-
rubygems_version: 3.
|
|
197
|
-
signing_key:
|
|
197
|
+
rubygems_version: 3.6.9
|
|
198
198
|
specification_version: 4
|
|
199
199
|
summary: Presents test results in a visual manner to guide you to where to look first.
|
|
200
200
|
test_files: []
|