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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 502a20709d4fe294ae357bd9652fa9442c14b851
4
- data.tar.gz: 8dabffcbda862538f2f3b3791b00b880ed2e9be5
3
+ metadata.gz: 12af0343c9c23e6c0e1ac4b5d513417855dbfdea
4
+ data.tar.gz: 5ad485865fe4165c3962971c33b4e0e1610bd21b
5
5
  SHA512:
6
- metadata.gz: f499bc2afd237666020abca95c8938f94a57955906f96340be86c0a67a54e1a09d8862329309eb2c672195360282aff51ab8a22a9555deac9bf923ec1f1ad226
7
- data.tar.gz: 2bbd0c0bf81e0ed3fd07aa3eef2552468381e3fccd88b42ca0adc477b2eec10cb3ff6edb2070612b4d826820f655547e204fbb2bf5c8f94a29e20ae455a4eb15
6
+ metadata.gz: ddad810a03f2ad851f9107f6b4eb18a4c0c459da0f91284764507b3a19103d1c60df319a61a45f6cfc56a2b47f30e2e8d7ddc5a6859149cb6bb980ab9247b868
7
+ data.tar.gz: dd0986ce38c6b8902389aa43f3f4957ccee503575ce14a8fd9cc4cdde5a2591b56c70546ce4c88297449b7786a4210d99763c1e9a8d4471d4134291af77f835b
data/.rspec CHANGED
@@ -1,5 +1,4 @@
1
1
  --colour
2
- --fail-fast
3
2
  --require error_to_communicate/at_exit
4
3
  --require error_to_communicate/rspec_formatter
5
4
  --format WhatWeveGotHereIsAnErrorToCommunicate::RSpecFormatter
data/Rakefile CHANGED
@@ -1,6 +1,18 @@
1
1
  #!/usr/bin/env rake
2
- require File.join('rspec', 'core', 'rake_task')
2
+ task :default => :spec
3
3
 
4
- RSpec::Core::RakeTask.new(:spec)
4
+ desc 'Run all tests'
5
+ task(:spec) { sh 'rspec' }
5
6
 
6
- task :default => :spec
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
- # Freezing this to encourage duping it rather than modifying the global default.
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
- ].freeze
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(exception)
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
- (exception.backtrace||[])
93
- .map { |line| Location.parse line }
94
- .tap { |locs| locs.each_cons(2) { |crnt, pred| crnt.pred, pred.succ = pred, crnt } }
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: location.linenum
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, -1
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 + 1 # 1 for the colon
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
- formatted_num = "#{num}:".ljust(linenum_width)
134
- formatted_num = theme.mark_linenum formatted_num if line_to_mark == num
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 :einfo, :project
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 explanation
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
  ]
@@ -10,7 +10,7 @@ module ErrorToCommunicate
10
10
  end
11
11
 
12
12
  def path
13
- @path ||= Pathname.new einfo.message.split(' -- ', 2).last
13
+ @path ||= Pathname.new message.split(' -- ', 2).last
14
14
  end
15
15
 
16
16
  def semantic_info
@@ -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 einfo
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(einfo)
31
- einfo.message[/`(.*)'/, 1]
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(einfo.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(einfo)
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(einfo)
64
- case einfo.message
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
- result = "\nFailures:\n"
26
- notification.failure_notifications.each_with_index do |failure, failure_number|
27
- # get the exception with the modified backtrace
28
- exception = failure.exception.dup
29
- metadata = failure.example.metadata
30
- exception.set_backtrace RSpec.configuration
31
- .backtrace_formatter
32
- .format_backtrace(exception.backtrace, metadata)
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,3 +1,3 @@
1
1
  module ErrorToCommunicate
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
@@ -1,6 +1,6 @@
1
1
  require 'heuristic/spec_helper'
2
2
 
3
- RSpec.describe 'heuristics for the WrongNumberOfArguments', t:true, heuristic: true do
3
+ RSpec.describe 'heuristics for the WrongNumberOfArguments', heuristic: true do
4
4
  def heuristic_class
5
5
  ErrorToCommunicate::Heuristic::WrongNumberOfArguments
6
6
  end
@@ -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; "!#{einfo.message}!"; end
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') { fail }
77
+ example('world') { expect(1).to eq 2 }
78
78
  end
79
- expect(get_printed formatter).to match /1\)\s*GroupName\s*hello/
80
- expect(get_printed formatter).to match /2\)\s*GroupName\s*world/
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.2
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-05-29 00:00:00.000000000 Z
12
+ date: 2015-06-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rouge