what_weve_got_here_is_an_error_to_communicate 0.0.2 → 0.0.3
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/.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
|

|
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
|