minitest-heat 0.0.10 → 0.0.14

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,197 +2,178 @@
2
2
 
3
3
  module Minitest
4
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' represents the last line from the project's tests. It is further differentiated by
10
- # the line where the test is defined and the actual line of code in the test that geneated
11
- # the failure or exception
12
- # - 'source_code' represents the last line from the project's source code
13
- # - 'project' represents the last source line, but falls back to the last test line
14
- # - 'most_relevant' represents the most specific file to investigate starting with the source
15
- # code and then looking to the test code with final line of the backtrace as a fallback
5
+ # Consistent structure for extracting information about a given location. In addition to the
6
+ # pathname to the file and the line number in the file, it can also include information about
7
+ # the containing method or block and retrieve source code for the location.
16
8
  class Location
17
- TestDefinition = Struct.new(:pathname, :line_number) do
18
- def initialize(pathname, line_number)
19
- @pathname = Pathname(pathname)
20
- @line_number = Integer(line_number)
21
- super
22
- end
23
- end
9
+ UNRECOGNIZED = '(Unrecognized File)'
10
+ UNKNOWN_MODIFICATION_TIME = Time.at(0)
11
+ UNKNOWN_MODIFICATION_SECONDS = -1
24
12
 
25
- attr_reader :test_definition_location, :backtrace
13
+ attr_accessor :raw_pathname, :raw_line_number, :raw_container
26
14
 
27
- def initialize(test_definition_location, backtrace = [])
28
- @test_definition_location = TestDefinition.new(*test_definition_location)
29
- @backtrace = Backtrace.new(backtrace)
15
+ # Initialize a new Location
16
+ #
17
+ # @param [Pathname, String] pathname: the pathname to the file
18
+ # @param [Integer] line_number: the line number of the location within the file
19
+ # @param [String] container: nil the containing method or block for the issue
20
+ #
21
+ # @return [self]
22
+ def initialize(pathname:, line_number:, container: nil)
23
+ @raw_pathname = pathname
24
+ @raw_line_number = line_number
25
+ @raw_container = container
30
26
  end
31
27
 
32
- # Prints the pathname and line number of the location most likely to be the source of the
33
- # test failure
28
+ # Generates a formatted string describing the line of code similar to the original backtrace
34
29
  #
35
- # @return [String] ex. 'path/to/file.rb:12'
30
+ # @return [String] a consistently-formatted, human-readable string about the line of code
36
31
  def to_s
37
- "#{most_relevant_file}:#{most_relevant_failure_line}"
38
- end
39
-
40
- def local?
41
- broken_test? || proper_failure?
32
+ "#{absolute_path}#{filename}:#{line_number} in `#{container}`"
42
33
  end
43
34
 
44
- # Knows if the failure is contained within the test. For example, if there's bad code in a
45
- # test, and it raises an exception, then it's really a broken test rather than a proper
46
- # faiure.
35
+ # Generates a simplified location array with the pathname and line number
47
36
  #
48
- # @return [Boolean] true if final file in the backtrace is the same as the test location file
49
- def broken_test?
50
- !test_file.nil? && test_file == final_file
37
+ # @return [Array<Pathname, Integer>] a no-frills location pair
38
+ def to_a
39
+ [
40
+ pathname,
41
+ line_number
42
+ ]
51
43
  end
52
44
 
53
- # Knows if the failure occurred in the actual project source code—as opposed to the test or
54
- # an external piece of code like a gem.
45
+ # A short relative pathname and line number pair
55
46
  #
56
- # @return [Boolean] true if there's a non-test project file in the stacktrace but it's not
57
- # a result of a broken test
58
- def proper_failure?
59
- !source_code_file.nil? && !broken_test?
47
+ # @return [String] the short filename/line number combo. ex. `dir/file.rb:23`
48
+ def short
49
+ "#{relative_filename}:#{line_number}"
60
50
  end
61
51
 
62
-
63
-
64
- # The final location of the stacktrace regardless of whether it's from within the project
52
+ # Determine if there is a file and text at the given line number
65
53
  #
66
- # @return [String] the relative path to the file from the project root
67
- def final_file
68
- Pathname(final_location.pathname)
54
+ # @return [Boolean] true if the file exists and has text at the given line number
55
+ def exists?
56
+ pathname.exist? && source_code.lines.any?
69
57
  end
70
58
 
71
- # The file most likely to be the source of the underlying problem. Often, the most recent
72
- # backtrace files will be a gem or external library that's failing indirectly as a result
73
- # of a problem with local source code (not always, but frequently). In that case, the best
74
- # first place to focus is on the code you control.
59
+ # The pathanme for the location. Written to be safe and fallbackto the project directory if
60
+ # an exception is raised ocnverting the value to a pathname
75
61
  #
76
- # @return [String] the relative path to the file from the project root
77
- def most_relevant_file
78
- Pathname(most_relevant_location.pathname)
62
+ # @return [Pathname] a pathname instance for the relevant file
63
+ def pathname
64
+ Pathname(raw_pathname)
65
+ rescue ArgumentError
66
+ Pathname(Dir.pwd)
79
67
  end
80
68
 
81
- # The final location from the stacktrace that is a test file
69
+ # A safe interface to getting a string representing the path portion of the file
82
70
  #
83
- # @return [String, nil] the relative path to the file from the project root
84
- def test_file
85
- Pathname(final_test_location.pathname)
71
+ # @return [String] either the path/directory portion of the file name or '(Unrecognized File)'
72
+ # if the offending file can't be found for some reason
73
+ def path
74
+ pathname.exist? ? pathname.dirname.to_s : UNRECOGNIZED
86
75
  end
87
76
 
88
- # The final location from the stacktrace that is within the project directory
89
- #
90
- # @return [String, nil] the relative path to the file from the project root
91
- def source_code_file
92
- return nil if final_source_code_location.nil?
77
+ def absolute_path
78
+ pathname.exist? ? "#{path}/" : UNRECOGNIZED
79
+ end
93
80
 
94
- Pathname(final_source_code_location.pathname)
81
+ def relative_path
82
+ pathname.exist? ? absolute_path.delete_prefix("#{project_root_dir}/") : UNRECOGNIZED
95
83
  end
96
84
 
97
- # The final location of the stacktrace from within the project (source code or test code)
85
+ # A safe interface for getting a string representing the filename portion of the file
98
86
  #
99
- # @return [String] the relative path to the file from the project root
100
- def project_file
101
- return nil if project_location.nil?
102
-
103
- Pathname(project_location.pathname)
87
+ # @return [String] either the filename portion of the file or '(Unrecognized File)'
88
+ # if the offending file can't be found for some reason
89
+ def filename
90
+ pathname.exist? ? pathname.basename.to_s : UNRECOGNIZED
104
91
  end
105
92
 
93
+ def absolute_filename
94
+ pathname.exist? ? pathname.to_s : UNRECOGNIZED
95
+ end
106
96
 
107
- # The line number of the `final_file` where the failure originated
108
- #
109
- # @return [Integer] line number
110
- def final_failure_line
111
- final_location.line_number
97
+ def relative_filename
98
+ pathname.exist? ? pathname.to_s.delete_prefix("#{project_root_dir}/") : UNRECOGNIZED
112
99
  end
113
100
 
114
- # The line number of the `most_relevant_file` where the failure originated
101
+ # Line number identifying the specific line in the file
115
102
  #
116
- # @return [Integer] line number
117
- def most_relevant_failure_line
118
- most_relevant_location.line_number
103
+ # @return [Integer] line number for the file
104
+ #
105
+ def line_number
106
+ Integer(raw_line_number)
107
+ rescue ArgumentError
108
+ 1
119
109
  end
120
110
 
121
- # The line number of the `test_file` where the test is defined
111
+ # The containing method or block details for the location
122
112
  #
123
- # @return [Integer] line number
124
- def test_definition_line
125
- test_definition_location.line_number
113
+ # @return [String] the containing method of the line of code
114
+ def container
115
+ raw_container.nil? ? '(Unknown Container)' : String(raw_container)
126
116
  end
127
117
 
128
- # The line number from within the `test_file` test definition where the failure occurred
118
+ # Looks up the source code for the location. Can return multiple lines of source code from
119
+ # the surrounding lines of code for the primary line
120
+ #
121
+ # @param [Integer] max_line_count: 1 the maximum number of lines to return from the source
129
122
  #
130
- # @return [Integer] line number
131
- def test_failure_line
132
- final_test_location.line_number
123
+ # @return [Source] an instance of Source for accessing lines and their line numbers
124
+ def source_code(max_line_count: 1)
125
+ Minitest::Heat::Source.new(
126
+ pathname.to_s,
127
+ line_number: line_number,
128
+ max_line_count: max_line_count
129
+ )
133
130
  end
134
131
 
135
- # The line number of the `source_code_file` where the failure originated
132
+ # Determines if a given file is from the project directory
136
133
  #
137
- # @return [Integer] line number
138
- def source_code_failure_line
139
- final_source_code_location&.line_number
134
+ # @return [Boolean] true if the file is in the project (source code or test)
135
+ def project_file?
136
+ path.include?(project_root_dir)
140
137
  end
141
138
 
142
- # The line number of the `project_file` where the failure originated
139
+ # Determines if a given file follows the standard approaching to naming test files.
143
140
  #
144
- # @return [Integer] line number
145
- def project_failure_line
146
- if !broken_test? && !source_code_file.nil?
147
- source_code_failure_line
148
- else
149
- test_failure_line
150
- end
141
+ # @return [Boolean] true if the file name starts with `test_` or ends with `_test.rb`
142
+ def test_file?
143
+ filename.to_s.start_with?('test_') || filename.to_s.end_with?('_test.rb')
151
144
  end
152
145
 
153
- # The line number from within the `test_file` test definition where the failure occurred
146
+ # Determines if a given file is a non-test file from the project directory
154
147
  #
155
- # @return [Location] the last location from the backtrace or the test location if a backtrace
156
- # was not passed to the initializer
157
- def final_location
158
- backtrace.parsed_entries.any? ? backtrace.final_location : test_definition_location
148
+ # @return [Boolean] true if the file is in the project but not a test file
149
+ def source_code_file?
150
+ project_file? && !test_file?
159
151
  end
160
152
 
161
- # The file most likely to be the source of the underlying problem. Often, the most recent
162
- # backtrace files will be a gem or external library that's failing indirectly as a result
163
- # of a problem with local source code (not always, but frequently). In that case, the best
164
- # first place to focus is on the code you control.
153
+ # A safe interface to getting the last modified time for the file in question
165
154
  #
166
- # @return [Array] file and line number of the most likely source of the problem
167
- def most_relevant_location
168
- [
169
- final_source_code_location,
170
- final_test_location,
171
- final_location
172
- ].compact.first
155
+ # @return [Time] the timestamp for when the file in question was last modified or `Time.at(0)`
156
+ # if the offending file can't be found for some reason
157
+ def mtime
158
+ pathname.exist? ? pathname.mtime : UNKNOWN_MODIFICATION_TIME
173
159
  end
174
160
 
175
- # Returns the final test location based on the backtrace if present. Otherwise falls back to
176
- # the test location which represents the test definition.
161
+ # A safe interface to getting the number of seconds since the file was modified
177
162
  #
178
- # @return [Location] the final location from the test files
179
- def final_test_location
180
- backtrace.final_test_location || test_definition_location
163
+ # @return [Integer] the number of seconds since the file was modified or `-1` if the offending
164
+ # file can't be found for some reason
165
+ def age_in_seconds
166
+ pathname.exist? ? seconds_ago : UNKNOWN_MODIFICATION_SECONDS
181
167
  end
182
168
 
183
- # Returns the final source code location based on the backtrace
184
- #
185
- # @return [Location] the final location from the source code files
186
- def final_source_code_location
187
- backtrace.final_source_code_location
169
+ private
170
+
171
+ def project_root_dir
172
+ Dir.pwd
188
173
  end
189
174
 
190
- # Returns the final project location based on the backtrace if present. Otherwise falls back
191
- # to the test location which represents the test definition.
192
- #
193
- # @return [Location] the final location from the project files
194
- def project_location
195
- backtrace.final_project_location || test_definition_location
175
+ def seconds_ago
176
+ (Time.now - mtime).to_i
196
177
  end
197
178
  end
198
179
  end
@@ -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
@@ -18,10 +18,9 @@ module Minitest
18
18
  # @param type [Symbol] the type of issue that was encountered (i.e. :failure, :error, etc.)
19
19
  #
20
20
  # @return [void]
21
- def add(filename, line_number, type)
22
- @hits[filename] ||= Hit.new(filename)
23
-
24
- @hits[filename].log(type.to_sym, line_number)
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)
25
24
  end
26
25
 
27
26
  # Returns a subset of affected files to keep the list from being overwhelming
@@ -3,115 +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 :location, :backtrace
11
+ attr_accessor :locations, :backtrace
12
12
 
13
- def initialize(location)
14
- @location = location
15
- @backtrace = location.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
- backtrace_entries.each do |backtrace_entry|
25
- # Get the source code for the line from the backtrace
26
- parts = backtrace_line_tokens(backtrace_entry)
27
-
28
- # If it's the most recently modified file in the trace, add the token for that
29
- parts << file_freshness(backtrace_entry) if most_recently_modified?(backtrace_entry)
30
-
31
- @tokens << parts
32
- end
33
-
34
- @tokens
21
+ @tokens = backtrace_locations.map { |location| backtrace_location_tokens(location) }
35
22
  end
36
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
37
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.
38
35
  DEFAULT_LINE_COUNT
39
36
  end
40
37
 
41
- # This should probably be smart about what lines are displayed in a backtrace.
42
- # Maybe...
43
- # ...it could intelligently display the full back trace?
44
- # ...only the backtrace from the first/last line of project source?
45
- # ...it behaves a little different when it's a broken test vs. a true exception?
46
- # ...it could be smart about subtly flagging the lines that show up in the heat map frequently?
47
- # ...it could be influenced by a "compact" or "robust" reporter super-style?
48
- # ...it's smart about exceptions that were raised outside of the project?
49
- # ...it's smart about highlighting lines of code differently based on whether it's source code, test code, or external code?
50
- def backtrace_entries
51
- all_entries
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)
52
62
  end
53
63
 
54
64
  private
55
65
 
56
- def backtrace_line_tokens(backtrace_entry)
66
+ def backtrace_location_tokens(location)
57
67
  [
58
68
  indentation_token,
59
- path_token(backtrace_entry),
60
- *file_and_line_number_tokens(backtrace_entry),
61
- source_code_line_token(backtrace_entry.source_code)
62
- ]
63
- end
64
-
65
- def all_backtrace_entries_from_project?
66
- backtrace_entries.all? { |line| line.path.to_s.include?(project_root_dir) }
67
- end
68
-
69
- def project_root_dir
70
- Dir.pwd
71
- end
72
-
73
- def project_entries
74
- backtrace.project_entries.take(line_count)
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
75
75
  end
76
76
 
77
- def all_entries
78
- backtrace.parsed_entries.take(line_count)
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?)
79
82
  end
80
83
 
81
- def most_recently_modified?(line)
82
- # If there's more than one line being displayed, and the current line is the freshest
83
- backtrace_entries.size > 1 && line == backtrace.freshest_project_location
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
84
96
  end
85
97
 
86
98
  def indentation_token
87
99
  [:default, ' ' * indentation]
88
100
  end
89
101
 
90
- def path_token(line)
91
- style = line.to_s.include?(Dir.pwd) ? :default : :muted
92
- path = "#{line.path}/"
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
93
105
 
94
- # If all of the backtrace lines are from the project, no point in the added redundant
95
- # noise of showing the project root directory over and over again
96
- path = path.delete_prefix(project_root_dir) if all_backtrace_entries_from_project?
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
97
109
 
98
- [style, path]
110
+ [style, location.send(path_format)]
99
111
  end
100
112
 
101
- def file_and_line_number_tokens(backtrace_entry)
102
- style = backtrace_entry.to_s.include?(Dir.pwd) ? :bold : :muted
113
+ def file_and_line_number_tokens(location)
114
+ style = location.to_s.include?(Dir.pwd) ? :bold : :muted
103
115
  [
104
- [style, backtrace_entry.file],
116
+ [style, location.filename],
105
117
  [:muted, ':'],
106
- [style, backtrace_entry.line_number]
118
+ [style, location.line_number]
107
119
  ]
108
120
  end
109
121
 
110
- def source_code_line_token(source_code)
111
- [:muted, " #{Output::SYMBOLS[:arrow]} `#{source_code.line.strip}`"]
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}`"]
126
+ end
127
+
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}"]
112
132
  end
113
133
 
114
- def file_freshness(_line)
134
+ def most_recently_modified_token(location)
135
+ return nil unless most_recently_modified?(location)
136
+
115
137
  [:default, " #{Output::SYMBOLS[:middot]} Most Recently Modified File"]
116
138
  end
117
139
 
@@ -126,10 +148,6 @@ module Minitest
126
148
  def indentation
127
149
  DEFAULT_INDENTATION_SPACES
128
150
  end
129
-
130
- def style_for(path)
131
- path.to_s.include?(Dir.pwd) ? :default : :muted
132
- end
133
151
  end
134
152
  end
135
153
  end