what_weve_got_here_is_an_error_to_communicate 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/Rakefile +15 -3
- data/Readme.md +17 -0
- data/lib/error_to_communicate/config.rb +7 -2
- data/lib/error_to_communicate/exception_info.rb +8 -8
- data/lib/error_to_communicate/format_terminal.rb +14 -8
- data/lib/error_to_communicate/heuristic.rb +13 -2
- data/lib/error_to_communicate/heuristic/load_error.rb +1 -1
- data/lib/error_to_communicate/heuristic/no_method_error.rb +4 -4
- data/lib/error_to_communicate/heuristic/syntax_error.rb +1 -1
- data/lib/error_to_communicate/heuristic/wrong_number_of_arguments.rb +4 -4
- data/lib/error_to_communicate/rspec_formatter.rb +60 -17
- data/lib/error_to_communicate/version.rb +1 -1
- data/spec/heuristic/wrong_number_of_arguments_spec.rb +1 -1
- data/spec/heuristic_spec.rb +1 -5
- data/spec/parsing_exception_info_spec.rb +27 -0
- data/spec/rspec_formatter_spec.rb +117 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12af0343c9c23e6c0e1ac4b5d513417855dbfdea
|
4
|
+
data.tar.gz: 5ad485865fe4165c3962971c33b4e0e1610bd21b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddad810a03f2ad851f9107f6b4eb18a4c0c459da0f91284764507b3a19103d1c60df319a61a45f6cfc56a2b47f30e2e8d7ddc5a6859149cb6bb980ab9247b868
|
7
|
+
data.tar.gz: dd0986ce38c6b8902389aa43f3f4957ccee503575ce14a8fd9cc4cdde5a2591b56c70546ce4c88297449b7786a4210d99763c1e9a8d4471d4134291af77f835b
|
data/.rspec
CHANGED
data/Rakefile
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
|
2
|
+
task :default => :spec
|
3
3
|
|
4
|
-
|
4
|
+
desc 'Run all tests'
|
5
|
+
task(:spec) { sh 'rspec' }
|
5
6
|
|
6
|
-
|
7
|
+
namespace :spec do
|
8
|
+
def self.spec(name, tags, description)
|
9
|
+
desc description
|
10
|
+
task(name) { sh "rspec --tag #{tags}" }
|
11
|
+
end
|
12
|
+
spec :config, 'config', 'Test configuration'
|
13
|
+
spec :heuristic, 'heuristic', 'Test the heuristcs'
|
14
|
+
spec :einfo, 'einfo', 'Test exception info'
|
15
|
+
spec :formatters, 'rspec_formatter', 'Test the RSpec formatter'
|
16
|
+
spec :acceptance, 'acceptance', 'Run acceptance tests (expensive)'
|
17
|
+
spec :quick, '~acceptance', 'Run all specs except the acceptance tests (b/c they\'re slow)'
|
18
|
+
end
|
data/Readme.md
CHANGED
@@ -9,11 +9,26 @@ A screenshot of the code rendering an `ArgumentError`.
|
|
9
9
|
|
10
10
|
![screenshot](https://s3.amazonaws.com/josh.cheek/images/scratch/better-reuby-commandline-errors.png)
|
11
11
|
|
12
|
+
|
12
13
|
This is still early and Rough
|
13
14
|
-----------------------------
|
14
15
|
|
15
16
|
But I've been using it on its own test suite, and have to say it's compelling!
|
16
17
|
|
18
|
+
|
19
|
+
Using this with RSpec or [MRspec](https://github.com/JoshCheek/mrspec)
|
20
|
+
----------------------------------------------------------------------
|
21
|
+
|
22
|
+
Place this in your .rspec file :)
|
23
|
+
|
24
|
+
```
|
25
|
+
--colour
|
26
|
+
--require error_to_communicate/at_exit
|
27
|
+
--require error_to_communicate/rspec_formatter
|
28
|
+
--format WhatWeveGotHereIsAnErrorToCommunicate::RSpecFormatter
|
29
|
+
```
|
30
|
+
|
31
|
+
|
17
32
|
Inspirations:
|
18
33
|
-------------
|
19
34
|
|
@@ -23,6 +38,7 @@ Inspirations:
|
|
23
38
|
and then at Ruby Conf, she created [chatty_exceptions](https://github.com/kerrizor/chatty_exceptions)
|
24
39
|
which is in this same domain.
|
25
40
|
|
41
|
+
|
26
42
|
Related Projects:
|
27
43
|
-----------------
|
28
44
|
|
@@ -30,6 +46,7 @@ Related Projects:
|
|
30
46
|
gem gives you a nice interface like this for Rails.
|
31
47
|
* Koichi's [pretty_backtrace](https://github.com/ko1/pretty_backtrace)
|
32
48
|
|
49
|
+
|
33
50
|
License
|
34
51
|
--------
|
35
52
|
|
@@ -8,8 +8,13 @@ module ErrorToCommunicate
|
|
8
8
|
autoload :FormatTerminal, 'error_to_communicate/format_terminal'
|
9
9
|
|
10
10
|
class Config
|
11
|
-
#
|
11
|
+
# If you wind up needing to modify this global list, let me know!
|
12
|
+
# I figure there should be a way to add/remove heuristics on the Config instance,
|
13
|
+
# but I can't quite tell what will be needed or what it should look like.
|
12
14
|
# This implies we should provide a way to add/remove heuristics on the config itself.
|
15
|
+
# So I'm intentionally leaving this array unfrozen, to allow modification,
|
16
|
+
# so that anyone wanting to hack in their own heuristic isn't prevented,
|
17
|
+
# but if that happens, tell me so I can figure out how to add that functionality correctly!
|
13
18
|
require 'error_to_communicate/heuristic/wrong_number_of_arguments'
|
14
19
|
require 'error_to_communicate/heuristic/no_method_error'
|
15
20
|
require 'error_to_communicate/heuristic/load_error'
|
@@ -21,7 +26,7 @@ module ErrorToCommunicate
|
|
21
26
|
Heuristic::LoadError,
|
22
27
|
Heuristic::SyntaxError,
|
23
28
|
Heuristic::Exception,
|
24
|
-
]
|
29
|
+
]
|
25
30
|
|
26
31
|
# Should maybe also be an array, b/c there's no great way to add a proc to the blacklist,
|
27
32
|
# right now, it would have to check it's thing and then call the next one
|
@@ -22,9 +22,9 @@ class ErrorToCommunicate::ExceptionInfo::Location
|
|
22
22
|
def self.parse(line)
|
23
23
|
line =~ /^(.*?):(\d+):in `(.*?)'$/ # Are ^ and $ sufficient? Should be \A and (\Z or \z)?
|
24
24
|
ErrorToCommunicate::ExceptionInfo::Location.new(
|
25
|
-
path: $1,
|
26
|
-
linenum: $2.to_i,
|
27
|
-
label: $3,
|
25
|
+
path: ($1||""),
|
26
|
+
linenum: ($2||"-1").to_i,
|
27
|
+
label: ($3||line),
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
@@ -83,14 +83,14 @@ class ErrorToCommunicate::ExceptionInfo
|
|
83
83
|
new exception: exception,
|
84
84
|
classname: exception.class.name,
|
85
85
|
message: exception.message,
|
86
|
-
backtrace: parse_backtrace(exception)
|
86
|
+
backtrace: parse_backtrace(exception.backtrace)
|
87
87
|
end
|
88
88
|
|
89
|
-
def self.parse_backtrace(
|
89
|
+
def self.parse_backtrace(backtrace)
|
90
90
|
# Really, there are better methods, e.g. backtrace_locations,
|
91
91
|
# but they're unevenly implemented across versions and implementations
|
92
|
-
(
|
93
|
-
|
94
|
-
|
92
|
+
backtrace = (backtrace||[]).map { |line| Location.parse line }
|
93
|
+
backtrace.each_cons(2) { |crnt, pred| crnt.pred, pred.succ = pred, crnt }
|
94
|
+
backtrace
|
95
95
|
end
|
96
96
|
end
|
@@ -54,8 +54,6 @@ module ErrorToCommunicate
|
|
54
54
|
|
55
55
|
|
56
56
|
class Code
|
57
|
-
# TODO: Should this highlight the location?
|
58
|
-
|
59
57
|
attr_accessor :theme, :cwd
|
60
58
|
|
61
59
|
def initialize(attributes)
|
@@ -72,6 +70,11 @@ module ErrorToCommunicate
|
|
72
70
|
start_index = bound_num min: 0, num: line_index+attributes.fetch(:context).begin
|
73
71
|
message = attributes.fetch :message, ''
|
74
72
|
message_offset = line_index - start_index
|
73
|
+
if attributes.fetch(:mark, true)
|
74
|
+
mark_linenum = location.linenum
|
75
|
+
else
|
76
|
+
mark_linenum = -1
|
77
|
+
end
|
75
78
|
|
76
79
|
# first line gives the path
|
77
80
|
path_line = [
|
@@ -86,8 +89,7 @@ module ErrorToCommunicate
|
|
86
89
|
code = File.read(path).lines[start_index..end_index].join("")
|
87
90
|
code = remove_indentation code
|
88
91
|
code = theme.syntax_highlight code
|
89
|
-
code = prefix_linenos_to code, start_index.next, mark:
|
90
|
-
code = theme.indent code, " "
|
92
|
+
code = prefix_linenos_to code, start_index.next, mark: mark_linenum
|
91
93
|
code = add_message_to code, message_offset, theme.screaming_red(message)
|
92
94
|
code = theme.highlight_text code, message_offset, highlight
|
93
95
|
else
|
@@ -124,14 +126,18 @@ module ErrorToCommunicate
|
|
124
126
|
end
|
125
127
|
|
126
128
|
def prefix_linenos_to(code, start_linenum, options)
|
127
|
-
line_to_mark = options.fetch :mark
|
129
|
+
line_to_mark = options.fetch :mark
|
128
130
|
lines = code.lines
|
129
131
|
max_linenum = lines.count + start_linenum - 1 # 1 to translate to indexes
|
130
|
-
linenum_width = max_linenum.to_s.length +
|
132
|
+
linenum_width = max_linenum.to_s.length + 4 # 1 for the colon, 3 for the arrow/space
|
131
133
|
lines.zip(start_linenum..max_linenum)
|
132
134
|
.map { |line, num|
|
133
|
-
|
134
|
-
|
135
|
+
if line_to_mark == num
|
136
|
+
formatted_num = "-> #{num}:".ljust(linenum_width)
|
137
|
+
formatted_num = theme.mark_linenum formatted_num
|
138
|
+
else
|
139
|
+
formatted_num = " #{num}:".ljust(linenum_width)
|
140
|
+
end
|
135
141
|
theme.color_linenum(formatted_num) << " " << line
|
136
142
|
}.join("")
|
137
143
|
end
|
@@ -4,7 +4,7 @@ module ErrorToCommunicate
|
|
4
4
|
raise NotImplementedError, "#{self} needs to implement .for? (subclass responsibility)"
|
5
5
|
end
|
6
6
|
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :project, :einfo
|
8
8
|
|
9
9
|
def initialize(attributes)
|
10
10
|
self.einfo = attributes.fetch :einfo
|
@@ -19,14 +19,24 @@ module ErrorToCommunicate
|
|
19
19
|
einfo.backtrace
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
22
|
+
def message
|
23
23
|
einfo.message
|
24
24
|
end
|
25
25
|
|
26
|
+
# Is this really a thing that should be in toplevel heuristic?
|
27
|
+
def explanation
|
28
|
+
message
|
29
|
+
end
|
30
|
+
|
26
31
|
def semantic_explanation
|
27
32
|
explanation
|
28
33
|
end
|
29
34
|
|
35
|
+
# The responsibility of structuring should move to the heuristic
|
36
|
+
# Then, the classname and explanation can be separated from the
|
37
|
+
# summary and columns. Which allows us to compose heuristics
|
38
|
+
# by composing their columnal information, and placing it in our own
|
39
|
+
# structural format
|
30
40
|
def semantic_summary
|
31
41
|
[:summary, [
|
32
42
|
[:columns,
|
@@ -46,6 +56,7 @@ module ErrorToCommunicate
|
|
46
56
|
highlight: (location.pred && location.pred.label),
|
47
57
|
context: 0..0,
|
48
58
|
emphasis: :path,
|
59
|
+
mark: false,
|
49
60
|
}]
|
50
61
|
end
|
51
62
|
]
|
@@ -6,11 +6,11 @@ module ErrorToCommunicate
|
|
6
6
|
def self.for?(einfo)
|
7
7
|
( einfo.classname == 'NoMethodError' ||
|
8
8
|
einfo.classname == 'NameError'
|
9
|
-
) && parse_undefined_name(einfo)
|
9
|
+
) && parse_undefined_name(einfo.message)
|
10
10
|
end
|
11
11
|
|
12
12
|
def undefined_method_name
|
13
|
-
self.class.parse_undefined_name
|
13
|
+
self.class.parse_undefined_name message
|
14
14
|
end
|
15
15
|
|
16
16
|
def semantic_info
|
@@ -27,8 +27,8 @@ module ErrorToCommunicate
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
def self.parse_undefined_name(
|
31
|
-
|
30
|
+
def self.parse_undefined_name(message)
|
31
|
+
message[/`(.*)'/, 1]
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -15,7 +15,7 @@ module ErrorToCommunicate
|
|
15
15
|
self.reported_file ,
|
16
16
|
self.reported_line ,
|
17
17
|
self.unexpected ,
|
18
|
-
self.expected = self.class.parse_message(
|
18
|
+
self.expected = self.class.parse_message(message)
|
19
19
|
self.invalid_loc = ExceptionInfo::Location.new \
|
20
20
|
path: reported_file,
|
21
21
|
linenum: reported_line,
|
@@ -4,14 +4,14 @@ module ErrorToCommunicate
|
|
4
4
|
class Heuristic
|
5
5
|
class WrongNumberOfArguments < Heuristic
|
6
6
|
def self.for?(einfo)
|
7
|
-
extract_from einfo
|
7
|
+
extract_from einfo.message
|
8
8
|
end
|
9
9
|
|
10
10
|
attr_accessor :explanation, :num_expected, :num_received
|
11
11
|
|
12
12
|
def initialize(*)
|
13
13
|
super
|
14
|
-
self.num_received, self.num_expected = self.class.extract_from(
|
14
|
+
self.num_received, self.num_expected = self.class.extract_from(message)
|
15
15
|
self.explanation = 'Wrong number of arguments'
|
16
16
|
end
|
17
17
|
|
@@ -60,8 +60,8 @@ module ErrorToCommunicate
|
|
60
60
|
|
61
61
|
private
|
62
62
|
|
63
|
-
def self.extract_from(
|
64
|
-
case
|
63
|
+
def self.extract_from(message)
|
64
|
+
case message
|
65
65
|
when /^wrong number of arguments.*?\((\d+) for (\d+)\)$/ # MRI / JRuby
|
66
66
|
num_received, num_expected = $1.to_i, $2.to_i
|
67
67
|
when /^method '.*?': given (\d+).*? expected (\d+)$/ # RBX
|
@@ -2,6 +2,58 @@ require 'error_to_communicate'
|
|
2
2
|
require 'rspec/core/formatters/documentation_formatter'
|
3
3
|
|
4
4
|
module ErrorToCommunicate
|
5
|
+
class Heuristic::RSpecFailure < Heuristic
|
6
|
+
attr_accessor :failure, :failure_number, :config
|
7
|
+
attr_accessor :semantic_summary, :semantic_info
|
8
|
+
|
9
|
+
def initialize(attributes)
|
10
|
+
self.failure_number = attributes.fetch :failure_number
|
11
|
+
self.failure = attributes.fetch :failure
|
12
|
+
self.config = attributes.fetch :config
|
13
|
+
|
14
|
+
# initialize the heuristic
|
15
|
+
ExceptionInfo.parse(failure.exception).tap do |einfo|
|
16
|
+
einfo.backtrace = ExceptionInfo.parse_backtrace failure.formatted_backtrace
|
17
|
+
super einfo: einfo, project: config.project
|
18
|
+
end
|
19
|
+
|
20
|
+
if assertion?
|
21
|
+
# format it with our lib
|
22
|
+
self.semantic_info =
|
23
|
+
[:heuristic, [ # ":heuristic" is dumb, it's not a heuristic, it's an error message, Maybe we need a :section or something?
|
24
|
+
[:message, message.sub(/\A\n*/, "")],
|
25
|
+
*backtrace.take(1).map { |loc|
|
26
|
+
[:code, {location: loc, context: (-5..5), emphasis: :code}]
|
27
|
+
}
|
28
|
+
]]
|
29
|
+
|
30
|
+
self.semantic_summary =
|
31
|
+
[:summary, [
|
32
|
+
[:columns,
|
33
|
+
[:classname, failure_number], # TODO: not classname
|
34
|
+
[:classname, failure.description]]]] # TODO: not classname
|
35
|
+
else
|
36
|
+
# wrap the heuristic that would otherwise be chosen
|
37
|
+
heuristic = config.heuristic_for einfo
|
38
|
+
self.semantic_info = heuristic.semantic_info
|
39
|
+
self.semantic_summary =
|
40
|
+
[:summary, [
|
41
|
+
[:columns,
|
42
|
+
[:classname, failure_number], # TODO: not classname
|
43
|
+
[:classname, failure.description], # TODO: not classname
|
44
|
+
[:classname, heuristic.classname], # TODO: not classname
|
45
|
+
[:explanation, heuristic.semantic_explanation]]]]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def assertion?
|
50
|
+
# RSpec differentiates failures from assertions by whether RSpec is in the name:
|
51
|
+
# https://github.com/JoshCheek/mrspec/blob/2761ba2180eb5f71a9262f6d59ce20d7cc8a47c3/lib/mrspec/minitest_assertion_for_rspec.rb
|
52
|
+
classname =~ /RSpec/
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
5
57
|
class RSpecFormatter < RSpec::Core::Formatters::DocumentationFormatter
|
6
58
|
# Register for notifications from our parent classes
|
7
59
|
# http://rspec.info/documentation/3.2/rspec-core/RSpec/Core/Formatters.html
|
@@ -22,24 +74,15 @@ module ErrorToCommunicate
|
|
22
74
|
# FIXME: Needs to respect RSpec.configuration.color_enabled?
|
23
75
|
# but we can't currently turn colour off in our output
|
24
76
|
def dump_failures(notification)
|
25
|
-
|
26
|
-
notification.failure_notifications.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# format it with our lib
|
35
|
-
heuristic = ErrorToCommunicate::Config.default.heuristic_for exception
|
36
|
-
formatted = ErrorToCommunicate::Config.default.format heuristic, Dir.pwd
|
37
|
-
|
38
|
-
# fit it into the larger failure summary
|
39
|
-
result << "\n #{failure_number+1}) #{failure.description}\n"
|
40
|
-
result << formatted.chomp.gsub(/^/, ' ')
|
77
|
+
output.puts "\nFailures:\n"
|
78
|
+
notification.failure_notifications.each.with_index(1) do |failure, failure_number|
|
79
|
+
heuristic = Heuristic::RSpecFailure.new \
|
80
|
+
config: Config.default,
|
81
|
+
failure: failure,
|
82
|
+
failure_number: failure_number
|
83
|
+
formatted = Config.default.format heuristic, Dir.pwd
|
84
|
+
output.puts formatted.chomp.gsub(/^/, ' ')
|
41
85
|
end
|
42
|
-
output.puts result
|
43
86
|
end
|
44
87
|
end
|
45
88
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'heuristic/spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe 'heuristics for the WrongNumberOfArguments',
|
3
|
+
RSpec.describe 'heuristics for the WrongNumberOfArguments', heuristic: true do
|
4
4
|
def heuristic_class
|
5
5
|
ErrorToCommunicate::Heuristic::WrongNumberOfArguments
|
6
6
|
end
|
data/spec/heuristic_spec.rb
CHANGED
@@ -14,10 +14,6 @@ RSpec.describe 'Heuristic', heuristic: true do
|
|
14
14
|
expect { subclass.for? nil }.to raise_error NotImplementedError, /subclass/
|
15
15
|
end
|
16
16
|
|
17
|
-
it 'records the exception info as einfo' do
|
18
|
-
expect(instance.einfo).to equal einfo
|
19
|
-
end
|
20
|
-
|
21
17
|
it 'delegates classname, and backtrace to einfo' do
|
22
18
|
expect(instance.classname).to eq 'the classname'
|
23
19
|
expect(instance.backtrace.map { |loc| [loc.linenum] }).to eq [[12]]
|
@@ -29,7 +25,7 @@ RSpec.describe 'Heuristic', heuristic: true do
|
|
29
25
|
|
30
26
|
describe 'semantic methods' do
|
31
27
|
specify 'semantic_explanation defaults to the explanation' do
|
32
|
-
def instance.explanation; "!#{
|
28
|
+
def instance.explanation; "!#{message}!"; end
|
33
29
|
expect(instance.semantic_explanation).to eq "!the message!"
|
34
30
|
end
|
35
31
|
|
@@ -83,6 +83,33 @@ RSpec.describe 'Parsing exceptions to ExceptionInfo', einfo: true do
|
|
83
83
|
assert_parses_line line, label: "method1"
|
84
84
|
end
|
85
85
|
|
86
|
+
context 'fake backtraces (eg RSpec renders text in the `formatted_backtrace` to get it to print messages there)' do
|
87
|
+
it 'has an empty path, linenum of -1, the entire string is the label' do
|
88
|
+
a, b, c = parsed = ErrorToCommunicate::ExceptionInfo.parse_backtrace([
|
89
|
+
"/Users/josh/.gem/ruby/2.1.1/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb:29:in `block in autorun'",
|
90
|
+
"",
|
91
|
+
" Showing full backtrace because every line was filtered out.",
|
92
|
+
])
|
93
|
+
|
94
|
+
expect(parsed.map(&:path).map(&:to_s)).to eq [
|
95
|
+
"/Users/josh/.gem/ruby/2.1.1/gems/rspec-core-3.2.3/lib/rspec/core/runner.rb",
|
96
|
+
"",
|
97
|
+
"",
|
98
|
+
]
|
99
|
+
|
100
|
+
expect(parsed.map &:linenum).to eq [29, -1, -1]
|
101
|
+
|
102
|
+
expect(parsed.map &:label).to eq [
|
103
|
+
"block in autorun",
|
104
|
+
"",
|
105
|
+
" Showing full backtrace because every line was filtered out.",
|
106
|
+
]
|
107
|
+
|
108
|
+
expect(parsed.map &:pred).to eq [b, c, nil]
|
109
|
+
expect(parsed.map &:succ).to eq [nil, a, b]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
86
113
|
context 'random ass colons in the middle of like files and directories and shit' do
|
87
114
|
# $ mkdir 'a:b'
|
88
115
|
# $ echo 'begin; define_method("a:b") { |arg| }; send "a:b"; rescue Exception; p $!.backtrace; end' > 'a:b/c:d.rb'
|
@@ -74,18 +74,10 @@ RSpec.describe ErrorToCommunicate::RSpecFormatter, rspec_formatter: true do
|
|
74
74
|
formatter = new_formatter
|
75
75
|
run_specs_against formatter, 'GroupName' do
|
76
76
|
example('hello') { fail }
|
77
|
-
example('world') {
|
77
|
+
example('world') { expect(1).to eq 2 }
|
78
78
|
end
|
79
|
-
expect(get_printed formatter).to match /1\
|
80
|
-
expect(get_printed formatter).to match /2\
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'respects the backtrace formatter (ie the --backtrace flag)' do
|
84
|
-
# only need to check a failing example to show it uses RSpec's backtrace formatter
|
85
|
-
formatter = new_formatter
|
86
|
-
run_specs_against(formatter) { example { fail } }
|
87
|
-
expect(get_printed formatter)
|
88
|
-
.to_not include substring_that_would_only_be_in_full_backtrace
|
79
|
+
expect(get_printed formatter).to match /1\s*\|\s*GroupName\s*hello/
|
80
|
+
expect(get_printed formatter).to match /2\s*\|\s*GroupName\s*world/
|
89
81
|
end
|
90
82
|
|
91
83
|
it 'respects colour enabling/disabling' do
|
@@ -94,4 +86,118 @@ RSpec.describe ErrorToCommunicate::RSpecFormatter, rspec_formatter: true do
|
|
94
86
|
pending 'We don\'t yet have the ability to turn color printing on/off'
|
95
87
|
fail
|
96
88
|
end
|
89
|
+
|
90
|
+
|
91
|
+
mock_failure_notification = Struct.new :exception, :formatted_backtrace, :description
|
92
|
+
|
93
|
+
define_method :failure_for do |attrs|
|
94
|
+
message = attrs.fetch :message, "ZOMG!"
|
95
|
+
exception = attrs.fetch :exception do
|
96
|
+
case attrs.fetch :type, :assertion
|
97
|
+
when :assertion
|
98
|
+
RSpec::Expectations::ExpectationNotMetError.new message
|
99
|
+
when :argument_error
|
100
|
+
ArgumentError.new message
|
101
|
+
else raise "uhm: #{attrs.inspect}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
mock_failure_notification.new \
|
106
|
+
exception,
|
107
|
+
attrs.fetch(:formatted_backtrace) { ["/a:1:in `b'"] },
|
108
|
+
attrs.fetch(:description, "default-description")
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when the failure is an error' do
|
112
|
+
it 'prints the backtrace, respecting the backtrace formatter (ie the --backtrace flag)' do
|
113
|
+
# only need to check a failing example to show it uses RSpec's backtrace formatter
|
114
|
+
formatter = new_formatter
|
115
|
+
run_specs_against(formatter) { example { fail } }
|
116
|
+
expect(get_printed formatter)
|
117
|
+
.to_not include substring_that_would_only_be_in_full_backtrace
|
118
|
+
end
|
119
|
+
|
120
|
+
specify 'the summary is the failure number and description' do
|
121
|
+
config = ErrorToCommunicate::Config.new
|
122
|
+
heuristic = ErrorToCommunicate::Heuristic::RSpecFailure.new \
|
123
|
+
config: ErrorToCommunicate::Config.default,
|
124
|
+
failure: failure_for(description: 'DESC', type: :assertion),
|
125
|
+
failure_number: 999
|
126
|
+
summaryname, ((columnsname, *columns)) = heuristic.semantic_summary
|
127
|
+
expect(summaryname).to eq :summary
|
128
|
+
expect(columnsname).to eq :columns
|
129
|
+
expect(columns.map &:last).to eq [999, 'DESC']
|
130
|
+
end
|
131
|
+
|
132
|
+
specify 'the info is the error message and first line from the backtrace with some context' do
|
133
|
+
config = ErrorToCommunicate::Config.new
|
134
|
+
heuristic = ErrorToCommunicate::Heuristic::RSpecFailure.new \
|
135
|
+
config: ErrorToCommunicate::Config.default,
|
136
|
+
failure: failure_for(type: :assertion, message: 'MESSAGE', formatted_backtrace: ["/file:123:in `method'"]),
|
137
|
+
failure_number: 999
|
138
|
+
heuristicname, ((messagename, message), (codename, codeattrs), *rest) = heuristic.semantic_info
|
139
|
+
expect(heuristicname).to eq :heuristic
|
140
|
+
expect(messagename ).to eq :message
|
141
|
+
expect(message ).to eq 'MESSAGE'
|
142
|
+
expect(codename ).to eq :code
|
143
|
+
expect(codeattrs[:location].path.to_s).to eq '/file'
|
144
|
+
expect(codeattrs[:context]).to eq (-5..5)
|
145
|
+
expect(codeattrs[:emphasis]).to eq :code
|
146
|
+
expect(rest).to be_empty
|
147
|
+
end
|
148
|
+
|
149
|
+
specify 'it omits the backtrace line, if it DNE' do
|
150
|
+
config = ErrorToCommunicate::Config.new
|
151
|
+
heuristic = ErrorToCommunicate::Heuristic::RSpecFailure.new \
|
152
|
+
config: ErrorToCommunicate::Config.default,
|
153
|
+
failure_number: 999,
|
154
|
+
failure: failure_for(type: :assertion, message: 'MESSAGE', formatted_backtrace: [])
|
155
|
+
heuristicname, ((messagename, message), *rest) = heuristic.semantic_info
|
156
|
+
expect(heuristicname).to eq :heuristic
|
157
|
+
expect(messagename ).to eq :message
|
158
|
+
expect(message ).to eq 'MESSAGE'
|
159
|
+
expect(rest).to be_empty
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
context 'when the failure is an assertion' do
|
165
|
+
it 'prints the backtrace, respecting the backtrace formatter (ie the --backtrace flag)' do
|
166
|
+
# only need to check a failing example to show it uses RSpec's backtrace formatter
|
167
|
+
formatter = new_formatter
|
168
|
+
run_specs_against(formatter) { example { expect(1).to eq 2 } }
|
169
|
+
expect(get_printed formatter)
|
170
|
+
.to_not include substring_that_would_only_be_in_full_backtrace
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
specify 'summary is the failure number, description, classname and semantic_explanation from the correct handler' do
|
175
|
+
expect_any_instance_of(ErrorToCommunicate::Heuristic::WrongNumberOfArguments)
|
176
|
+
.to receive(:semantic_explanation).and_return("SEMANTICEXPLANATION")
|
177
|
+
|
178
|
+
heuristic = ErrorToCommunicate::Heuristic::RSpecFailure.new \
|
179
|
+
config: ErrorToCommunicate::Config.new,
|
180
|
+
failure: failure_for(message: "wrong number of arguments (1 for 0)",
|
181
|
+
description: 'DESC',
|
182
|
+
type: :argument_error),
|
183
|
+
failure_number: 999
|
184
|
+
summaryname, ((columnsname, *columns)) = heuristic.semantic_summary
|
185
|
+
expect(summaryname).to eq :summary
|
186
|
+
expect(columnsname).to eq :columns
|
187
|
+
expect(columns.map &:last).to eq [999, 'DESC', 'ArgumentError', 'SEMANTICEXPLANATION']
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
it 'delegates the heuristic to the correct handler' do
|
192
|
+
expect_any_instance_of(ErrorToCommunicate::Heuristic::WrongNumberOfArguments)
|
193
|
+
.to receive(:semantic_info).and_return("SEMANTICINFO")
|
194
|
+
|
195
|
+
heuristic = ErrorToCommunicate::Heuristic::RSpecFailure.new \
|
196
|
+
config: ErrorToCommunicate::Config.new,
|
197
|
+
failure: failure_for(message: "wrong number of arguments (1 for 0)", type: :argument_error),
|
198
|
+
failure_number: 999
|
199
|
+
|
200
|
+
expect(heuristic.semantic_info).to eq "SEMANTICINFO"
|
201
|
+
end
|
202
|
+
end
|
97
203
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: what_weve_got_here_is_an_error_to_communicate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Cheek
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-06-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rouge
|