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