minitest-heat 0.0.9 → 0.0.13
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/.rubocop.yml +1 -0
- data/Gemfile.lock +6 -6
- data/README.md +49 -14
- data/examples/exceptions.png +0 -0
- data/examples/failures.png +0 -0
- data/examples/map.png +0 -0
- data/examples/markers.png +0 -0
- data/examples/skips.png +0 -0
- data/examples/slows.png +0 -0
- data/lib/minitest/heat/backtrace/line_parser.rb +25 -0
- data/lib/minitest/heat/backtrace.rb +39 -43
- data/lib/minitest/heat/hit.rb +36 -19
- data/lib/minitest/heat/issue.rb +118 -81
- data/lib/minitest/heat/location.rb +115 -116
- data/lib/minitest/heat/locations.rb +105 -0
- data/lib/minitest/heat/map.rb +16 -4
- data/lib/minitest/heat/output/backtrace.rb +90 -67
- data/lib/minitest/heat/output/issue.rb +76 -67
- data/lib/minitest/heat/output/map.rb +127 -25
- data/lib/minitest/heat/output/marker.rb +5 -3
- data/lib/minitest/heat/output/results.rb +3 -2
- data/lib/minitest/heat/output/source_code.rb +1 -1
- data/lib/minitest/heat/output/token.rb +2 -1
- data/lib/minitest/heat/output.rb +76 -6
- data/lib/minitest/heat/results.rb +23 -3
- data/lib/minitest/heat/source.rb +1 -1
- data/lib/minitest/heat/version.rb +1 -1
- data/lib/minitest/heat.rb +3 -2
- data/lib/minitest/heat_plugin.rb +9 -17
- data/lib/minitest/heat_reporter.rb +25 -35
- metadata +11 -4
- data/lib/minitest/heat/line.rb +0 -74
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Minitest
|
4
|
+
module Heat
|
5
|
+
# Convenience methods for determining the file and line number where the problem occurred.
|
6
|
+
# There are several layers of specificity to help make it easy to communicate the relative
|
7
|
+
# location of the failure:
|
8
|
+
# - 'final' represents the final line of the backtrace regardless of where it is
|
9
|
+
# - 'test_definition' represents where the test is defined
|
10
|
+
# - 'test_failure' represents the last line from the project's tests. It is further differentiated by
|
11
|
+
# the line where the test is defined and the actual line of code in the test that geneated
|
12
|
+
# the failure or exception
|
13
|
+
# - 'source_code' represents the last line from the project's source code
|
14
|
+
# - 'project' represents the last source line, but falls back to the last test line
|
15
|
+
# - 'most_relevant' represents the most specific file to investigate starting with the source
|
16
|
+
# code and then looking to the test code with final line of the backtrace as a fallback
|
17
|
+
class Locations
|
18
|
+
attr_reader :test_definition, :backtrace
|
19
|
+
|
20
|
+
def initialize(test_definition_location, backtrace = [])
|
21
|
+
test_definition_pathname, test_definition_line_number = test_definition_location
|
22
|
+
@test_definition = ::Minitest::Heat::Location.new(pathname: test_definition_pathname, line_number: test_definition_line_number)
|
23
|
+
|
24
|
+
@backtrace = Backtrace.new(backtrace)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Prints the pathname and line number of the location most likely to be the source of the
|
28
|
+
# test failure
|
29
|
+
#
|
30
|
+
# @return [String] ex. 'path/to/file.rb:12'
|
31
|
+
def to_s
|
32
|
+
"#{most_relevant.absolute_filename}:#{most_relevant.line_number}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Knows if the failure is contained within the test. For example, if there's bad code in a
|
36
|
+
# test, and it raises an exception, then it's really a broken test rather than a proper
|
37
|
+
# faiure.
|
38
|
+
#
|
39
|
+
# @return [Boolean] true if final file in the backtrace is the same as the test location file
|
40
|
+
def broken_test?
|
41
|
+
!test_failure.nil? && test_failure == final
|
42
|
+
end
|
43
|
+
|
44
|
+
# Knows if the failure occurred in the actual project source code—as opposed to the test or
|
45
|
+
# an external piece of code like a gem.
|
46
|
+
#
|
47
|
+
# @return [Boolean] true if there's a non-test project file in the stacktrace but it's not
|
48
|
+
# a result of a broken test
|
49
|
+
def proper_failure?
|
50
|
+
!source_code.nil? && !broken_test?
|
51
|
+
end
|
52
|
+
|
53
|
+
# The file most likely to be the source of the underlying problem. Often, the most recent
|
54
|
+
# backtrace files will be a gem or external library that's failing indirectly as a result
|
55
|
+
# of a problem with local source code (not always, but frequently). In that case, the best
|
56
|
+
# first place to focus is on the code you control.
|
57
|
+
#
|
58
|
+
# @return [Array] file and line number of the most likely source of the problem
|
59
|
+
def most_relevant
|
60
|
+
[
|
61
|
+
source_code,
|
62
|
+
test_failure,
|
63
|
+
final
|
64
|
+
].compact.first
|
65
|
+
end
|
66
|
+
|
67
|
+
def freshest
|
68
|
+
backtrace.recently_modified_locations.first
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the final test location based on the backtrace if present. Otherwise falls back to
|
72
|
+
# the test location which represents the test definition. The `test_definition` attribute
|
73
|
+
# provides the location of where the test is defined. `test_failure` represents the actual
|
74
|
+
# line from within the test where the problem occurred
|
75
|
+
#
|
76
|
+
# @return [Location] the final location from the test files
|
77
|
+
def test_failure
|
78
|
+
backtrace.test_locations.any? ? backtrace.test_locations.first : test_definition
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the final source code location based on the backtrace
|
82
|
+
#
|
83
|
+
# @return [Location] the final location from the source code files
|
84
|
+
def source_code
|
85
|
+
backtrace.source_code_locations.first
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the final project location based on the backtrace if present. Otherwise falls back
|
89
|
+
# to the test location which represents the test definition.
|
90
|
+
#
|
91
|
+
# @return [Location] the final location from the project files
|
92
|
+
def project
|
93
|
+
backtrace.project_locations.any? ? backtrace.project_locations.first : test_definition
|
94
|
+
end
|
95
|
+
|
96
|
+
# The line number from within the `test_file` test definition where the failure occurred
|
97
|
+
#
|
98
|
+
# @return [Location] the last location from the backtrace or the test location if a backtrace
|
99
|
+
# was not passed to the initializer
|
100
|
+
def final
|
101
|
+
backtrace.locations.any? ? backtrace.locations.first : test_definition
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/minitest/heat/map.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
|
+
# Structured approach to collecting the locations of issues for generating a heat map
|
5
6
|
class Map
|
6
7
|
MAXIMUM_FILES_TO_SHOW = 5
|
7
8
|
|
@@ -11,18 +12,29 @@ module Minitest
|
|
11
12
|
@hits = {}
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# Records a hit to the list of files and issue types
|
16
|
+
# @param filename [String] the unique path and file name for recordings hits
|
17
|
+
# @param line_number [Integer] the line number where the issue was encountered
|
18
|
+
# @param type [Symbol] the type of issue that was encountered (i.e. :failure, :error, etc.)
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def add(pathname, line_number, type, backtrace: [])
|
22
|
+
@hits[pathname.to_s] ||= Hit.new(pathname)
|
23
|
+
@hits[pathname.to_s].log(type.to_sym, line_number, backtrace: backtrace)
|
18
24
|
end
|
19
25
|
|
26
|
+
# Returns a subset of affected files to keep the list from being overwhelming
|
27
|
+
#
|
28
|
+
# @return [Array] the list of files and the line numbers for each encountered issue type
|
20
29
|
def file_hits
|
21
30
|
hot_files.take(MAXIMUM_FILES_TO_SHOW)
|
22
31
|
end
|
23
32
|
|
24
33
|
private
|
25
34
|
|
35
|
+
# Sorts the files by hit "weight" so that the most problematic files are at the beginning
|
36
|
+
#
|
37
|
+
# @return [Array] the collection of files that encountred issues
|
26
38
|
def hot_files
|
27
39
|
hits.values.sort_by(&:weight).reverse
|
28
40
|
end
|
@@ -3,110 +3,137 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
-
# Builds the collection of tokens for a backtrace when an exception occurs
|
6
|
+
# Builds the collection of tokens for displaying a backtrace when an exception occurs
|
7
7
|
class Backtrace
|
8
8
|
DEFAULT_LINE_COUNT = 10
|
9
9
|
DEFAULT_INDENTATION_SPACES = 2
|
10
10
|
|
11
|
-
attr_accessor :
|
11
|
+
attr_accessor :locations, :backtrace
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@
|
15
|
-
@backtrace =
|
13
|
+
def initialize(locations)
|
14
|
+
@locations = locations
|
15
|
+
@backtrace = locations.backtrace
|
16
16
|
@tokens = []
|
17
17
|
end
|
18
18
|
|
19
19
|
def tokens
|
20
|
-
# There could be option to expand and display more than one line of source code for the
|
21
|
-
# final backtrace line if it might be relevant/helpful?
|
22
|
-
|
23
20
|
# Iterate over the selected lines from the backtrace
|
24
|
-
|
25
|
-
# Get the source code for the line from the backtrace
|
26
|
-
parts = [
|
27
|
-
indentation_token,
|
28
|
-
path_token(backtrace_entry),
|
29
|
-
*file_and_line_number_tokens(backtrace_entry),
|
30
|
-
source_code_line_token(backtrace_entry.source_code)
|
31
|
-
]
|
32
|
-
|
33
|
-
parts << file_freshness(backtrace_entry) if most_recently_modified?(backtrace_entry)
|
34
|
-
|
35
|
-
@tokens << parts
|
36
|
-
end
|
37
|
-
|
38
|
-
@tokens
|
21
|
+
@tokens = backtrace_locations.map { |location| backtrace_location_tokens(location) }
|
39
22
|
end
|
40
23
|
|
24
|
+
# Determines the number of lines to display from the backtrace.
|
25
|
+
#
|
26
|
+
# @return [Integer] the number of lines to limit the backtrace to
|
41
27
|
def line_count
|
28
|
+
# Defined as a method instead of using the constant directlyr in order to easily support
|
29
|
+
# adding options for controlling how many lines are displayed from a backtrace.
|
30
|
+
#
|
31
|
+
# For example, instead of a fixed number, the backtrace could dynamically calculate how
|
32
|
+
# many lines it should displaye in order to get to the origination point. Or it could have
|
33
|
+
# a default, but inteligently go back further if the backtrace meets some criteria for
|
34
|
+
# displaying more lines.
|
42
35
|
DEFAULT_LINE_COUNT
|
43
36
|
end
|
44
37
|
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
38
|
+
# A subset of parsed lines from the backtrace.
|
39
|
+
#
|
40
|
+
# @return [Array<Location>] the backtrace locations determined to be most relevant to the
|
41
|
+
# context of the underlying issue
|
42
|
+
def backtrace_locations
|
43
|
+
# This could eventually have additional intelligence to determine what lines are most
|
44
|
+
# relevant for a given type of issue. For now, it simply takes the line numbers, but the
|
45
|
+
# idea is that long-term, it could adjust that on the fly to keep the line count as low
|
46
|
+
# as possible but expand it if necessary to ensure enough context is displayed.
|
47
|
+
#
|
48
|
+
# - If there's no clear cut details about the source of the error from within the project,
|
49
|
+
# it could display the entire backtrace without filtering anything.
|
50
|
+
# - It could scan the backtrace to the first appearance of project files and then display
|
51
|
+
# all of the lines that occurred after that instance
|
52
|
+
# - It coudl filter the lines differently whether the issue originated from a test or from
|
53
|
+
# the source code.
|
54
|
+
# - It could allow supporting a "compact" or "robust" reporter style so that someone on
|
55
|
+
# a smaller screen could easily reduce the information shown so that the results could
|
56
|
+
# be higher density even if it means truncating some occasionally useful details
|
57
|
+
# - It could be smarter about displaying context/guidance when the full backtrace is from
|
58
|
+
# outside the project's code
|
59
|
+
#
|
60
|
+
# But for now. It just grabs some lines.
|
61
|
+
backtrace.locations.take(line_count)
|
56
62
|
end
|
57
63
|
|
58
64
|
private
|
59
65
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
backtrace.project_entries.take(line_count)
|
66
|
+
def backtrace_location_tokens(location)
|
67
|
+
[
|
68
|
+
indentation_token,
|
69
|
+
path_token(location),
|
70
|
+
*file_and_line_number_tokens(location),
|
71
|
+
containining_element_token(location),
|
72
|
+
source_code_line_token(location),
|
73
|
+
most_recently_modified_token(location),
|
74
|
+
].compact
|
70
75
|
end
|
71
76
|
|
72
|
-
|
73
|
-
|
77
|
+
# Determines if all lines to be displayed are from within the project directory
|
78
|
+
#
|
79
|
+
# @return [Boolean] true if all lines of the backtrace being displayed are from the project
|
80
|
+
def all_backtrace_from_project?
|
81
|
+
backtrace_locations.all?(&:project_file?)
|
74
82
|
end
|
75
83
|
|
76
|
-
|
77
|
-
|
78
|
-
|
84
|
+
# Determines if the file referenced by a backtrace line is the most recently modified file
|
85
|
+
# of all the files referenced in the visible backtrace locations.
|
86
|
+
#
|
87
|
+
# @param [Location] location the location to examine
|
88
|
+
#
|
89
|
+
# @return [<type>] <description>
|
90
|
+
#
|
91
|
+
def most_recently_modified?(location)
|
92
|
+
# If there's more than one line being displayed (otherwise, with one line, of course it's
|
93
|
+
# the most recently modified because there_aren't any others) and the current line is the
|
94
|
+
# same as the freshest location in the backtrace
|
95
|
+
backtrace_locations.size > 1 && location == locations.freshest
|
79
96
|
end
|
80
97
|
|
81
98
|
def indentation_token
|
82
99
|
[:default, ' ' * indentation]
|
83
100
|
end
|
84
101
|
|
85
|
-
def path_token(
|
86
|
-
|
87
|
-
|
102
|
+
def path_token(location)
|
103
|
+
# If the line is a project file, help it stand out from the backtrace noise
|
104
|
+
style = location.project_file? ? :default : :muted
|
88
105
|
|
89
|
-
# If all of the backtrace lines are from the project, no point in the added redundant
|
90
|
-
#
|
91
|
-
|
106
|
+
# If *all* of the backtrace lines are from the project, no point in the added redundant
|
107
|
+
# noise of showing the project root directory over and over again
|
108
|
+
path_format = all_backtrace_from_project? ? :relative_path : :absolute_path
|
92
109
|
|
93
|
-
[style,
|
110
|
+
[style, location.send(path_format)]
|
94
111
|
end
|
95
112
|
|
96
|
-
def file_and_line_number_tokens(
|
97
|
-
style =
|
113
|
+
def file_and_line_number_tokens(location)
|
114
|
+
style = location.to_s.include?(Dir.pwd) ? :bold : :muted
|
98
115
|
[
|
99
|
-
[style,
|
116
|
+
[style, location.filename],
|
100
117
|
[:muted, ':'],
|
101
|
-
[style,
|
118
|
+
[style, location.line_number]
|
102
119
|
]
|
103
120
|
end
|
104
121
|
|
105
|
-
def source_code_line_token(
|
106
|
-
|
122
|
+
def source_code_line_token(location)
|
123
|
+
return nil unless location.project_file?
|
124
|
+
|
125
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} `#{location.source_code.line.strip}`"]
|
107
126
|
end
|
108
127
|
|
109
|
-
def
|
128
|
+
def containining_element_token(location)
|
129
|
+
return nil if !location.project_file? || location.container.nil? || location.container.empty?
|
130
|
+
|
131
|
+
[:muted, " in #{location.container}"]
|
132
|
+
end
|
133
|
+
|
134
|
+
def most_recently_modified_token(location)
|
135
|
+
return nil unless most_recently_modified?(location)
|
136
|
+
|
110
137
|
[:default, " #{Output::SYMBOLS[:middot]} Most Recently Modified File"]
|
111
138
|
end
|
112
139
|
|
@@ -121,10 +148,6 @@ module Minitest
|
|
121
148
|
def indentation
|
122
149
|
DEFAULT_INDENTATION_SPACES
|
123
150
|
end
|
124
|
-
|
125
|
-
def style_for(path)
|
126
|
-
style = path.to_s.include?(Dir.pwd) ? :default : :muted
|
127
|
-
end
|
128
151
|
end
|
129
152
|
end
|
130
153
|
end
|
@@ -3,37 +3,27 @@
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
5
|
class Output
|
6
|
-
|
7
|
-
|
6
|
+
# Formats issues to output based on the issue type
|
7
|
+
class Issue # rubocop:disable Metrics/ClassLength
|
8
|
+
attr_accessor :issue, :locations
|
8
9
|
|
9
10
|
def initialize(issue)
|
10
11
|
@issue = issue
|
12
|
+
@locations = issue.locations
|
11
13
|
end
|
12
14
|
|
13
15
|
def tokens
|
14
16
|
case issue.type
|
15
|
-
when :error then
|
16
|
-
when :
|
17
|
-
when :
|
18
|
-
when :
|
19
|
-
when :painful then painful_tokens
|
20
|
-
when :slow then slow_tokens
|
17
|
+
when :error, :broken then exception_tokens
|
18
|
+
when :failure then failure_tokens
|
19
|
+
when :skipped then skipped_tokens
|
20
|
+
when :painful, :slow then slow_tokens
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
def
|
27
|
-
[
|
28
|
-
headline_tokens,
|
29
|
-
test_location_tokens,
|
30
|
-
summary_tokens,
|
31
|
-
*backtrace_tokens,
|
32
|
-
newline_tokens
|
33
|
-
]
|
34
|
-
end
|
35
|
-
|
36
|
-
def broken_tokens
|
26
|
+
def exception_tokens
|
37
27
|
[
|
38
28
|
headline_tokens,
|
39
29
|
test_location_tokens,
|
@@ -60,14 +50,6 @@ module Minitest
|
|
60
50
|
]
|
61
51
|
end
|
62
52
|
|
63
|
-
def painful_tokens
|
64
|
-
[
|
65
|
-
headline_tokens,
|
66
|
-
slowness_summary_tokens,
|
67
|
-
newline_tokens
|
68
|
-
]
|
69
|
-
end
|
70
|
-
|
71
53
|
def slow_tokens
|
72
54
|
[
|
73
55
|
headline_tokens,
|
@@ -77,75 +59,82 @@ module Minitest
|
|
77
59
|
end
|
78
60
|
|
79
61
|
def headline_tokens
|
80
|
-
[
|
62
|
+
[label_token(issue), spacer_token, [:default, test_name(issue)]]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Creates a display-friendly version of the test name with underscores removed and the
|
66
|
+
# first letter capitalized regardless of the formatt used for the test definition
|
67
|
+
# @param issue [Issue] the issue to use to generate the test name
|
68
|
+
#
|
69
|
+
# @return [String] the cleaned up version of the test name
|
70
|
+
def test_name(issue)
|
71
|
+
test_prefix = 'test_'
|
72
|
+
identifier = issue.test_identifier
|
73
|
+
|
74
|
+
if identifier.start_with?(test_prefix)
|
75
|
+
identifier.delete_prefix(test_prefix).gsub('_', ' ').capitalize
|
76
|
+
else
|
77
|
+
identifier
|
78
|
+
end
|
81
79
|
end
|
82
80
|
|
83
|
-
def
|
84
|
-
[
|
81
|
+
def label_token(issue)
|
82
|
+
[issue.type, issue_label(issue.type)]
|
85
83
|
end
|
86
84
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
backtrace.tokens
|
85
|
+
def test_name_and_class_tokens
|
86
|
+
[[:default, issue.test_class], *test_location_tokens]
|
91
87
|
end
|
92
88
|
|
93
89
|
def test_location_tokens
|
94
|
-
[
|
90
|
+
[
|
91
|
+
[:default, locations.test_definition.relative_filename],
|
92
|
+
[:muted, ':'],
|
93
|
+
[:default, locations.test_definition.line_number],
|
94
|
+
arrow_token,
|
95
|
+
[:default, locations.test_failure.line_number],
|
96
|
+
[:muted, "\n #{locations.test_failure.source_code.line.strip}"]
|
97
|
+
]
|
95
98
|
end
|
96
99
|
|
97
100
|
def location_tokens
|
98
|
-
[
|
101
|
+
[
|
102
|
+
[:default, locations.most_relevant.relative_filename],
|
103
|
+
[:muted, ':'],
|
104
|
+
[:default, locations.most_relevant.line_number],
|
105
|
+
[:muted, "\n #{locations.most_relevant.source_code.line.strip}"]
|
106
|
+
]
|
99
107
|
end
|
100
108
|
|
101
109
|
def source_tokens
|
102
|
-
filename =
|
103
|
-
line_number =
|
104
|
-
|
110
|
+
filename = locations.project.filename
|
111
|
+
line_number = locations.project.line_number
|
105
112
|
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
113
|
+
|
106
114
|
[[:muted, " #{Output::SYMBOLS[:arrow]} `#{source.line.strip}`"]]
|
107
115
|
end
|
108
116
|
|
109
117
|
def summary_tokens
|
110
|
-
[[:italicized, issue.summary.delete_suffix(
|
118
|
+
[[:italicized, issue.summary.delete_suffix('---------------').strip]]
|
111
119
|
end
|
112
120
|
|
113
121
|
def slowness_summary_tokens
|
114
122
|
[
|
115
|
-
[:bold, issue
|
123
|
+
[:bold, slowness(issue)],
|
116
124
|
spacer_token,
|
117
|
-
[:default,
|
125
|
+
[:default, locations.test_definition.relative_path],
|
126
|
+
[:default, locations.test_definition.filename],
|
118
127
|
[:muted, ':'],
|
119
|
-
[:default,
|
128
|
+
[:default, locations.test_definition.line_number]
|
120
129
|
]
|
121
130
|
end
|
122
131
|
|
123
|
-
def
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
def most_relevant_short_location
|
128
|
-
issue.location.most_relevant_file.to_s.delete_prefix("#{Dir.pwd}/")
|
129
|
-
end
|
130
|
-
|
131
|
-
def test_file_short_location
|
132
|
-
issue.location.test_file.to_s.delete_prefix("#{Dir.pwd}/")
|
132
|
+
def slowness(issue)
|
133
|
+
"#{issue.execution_time.round(2)}s"
|
133
134
|
end
|
134
135
|
|
135
|
-
def
|
136
|
-
|
137
|
-
line_number = issue.location.project_failure_line
|
138
|
-
|
139
|
-
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
140
|
-
"\n #{source.line.strip}"
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_line_source
|
144
|
-
filename = issue.location.test_file
|
145
|
-
line_number = issue.location.test_failure_line
|
146
|
-
|
147
|
-
source = Minitest::Heat::Source.new(filename, line_number: line_number)
|
148
|
-
"\n #{source.line.strip}"
|
136
|
+
def newline_tokens
|
137
|
+
[]
|
149
138
|
end
|
150
139
|
|
151
140
|
def spacer_token
|
@@ -156,6 +145,26 @@ module Minitest
|
|
156
145
|
Output::TOKENS[:muted_arrow]
|
157
146
|
end
|
158
147
|
|
148
|
+
def backtrace_tokens
|
149
|
+
@backtrace_tokens ||= ::Minitest::Heat::Output::Backtrace.new(locations).tokens
|
150
|
+
end
|
151
|
+
|
152
|
+
# The string to use to describe the failure type when displaying results/
|
153
|
+
# @param issue_type [Symbol] the symbol representing the issue's failure type
|
154
|
+
#
|
155
|
+
# @return [String] the display-friendly string describing the failure reason
|
156
|
+
def issue_label(issue_type)
|
157
|
+
case issue_type
|
158
|
+
when :error then 'Error'
|
159
|
+
when :broken then 'Broken Test'
|
160
|
+
when :failure then 'Failure'
|
161
|
+
when :skipped then 'Skipped'
|
162
|
+
when :slow then 'Passed but Slow'
|
163
|
+
when :painful then 'Passed but Very Slow'
|
164
|
+
when :passed then 'Success'
|
165
|
+
else 'Unknown'
|
166
|
+
end
|
167
|
+
end
|
159
168
|
end
|
160
169
|
end
|
161
170
|
end
|