seeing_is_believing 3.0.0.beta.2 → 3.0.0.beta.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: 981bfb703701767923dee2010cd2073ec901e20f
4
- data.tar.gz: 0eaa0290fac0e7b0b312196371507f717b2ad1d7
3
+ metadata.gz: d2e468be6e5df6cd6e01b6c6d000e204adea080f
4
+ data.tar.gz: 27401d23d03170455703d30a285e8a55726c0192
5
5
  SHA512:
6
- metadata.gz: 019b0ac6587cb94c98bc9e916daa49f8b21e6eba166a3a6c5e930de573ecce274004f11de8cd47e366af46c4da881376b05c4ef4d3a8a43a5e0c614517a53d75
7
- data.tar.gz: d515e9959c12741755f0ff298a5f571d8860290a15f3548e3386ae7ef8b4b9c0364ccac1c7a7816a771fc9a100746f813e259dce2cac943d01c6f8d70510dc1d
6
+ metadata.gz: 572bad143fd60f08c04b43289143f46ade1121300b6073830107ce183aef58741bd1acd3b1d75544d2af878df4802346e2e1a921b5e60464b7eddfb69498e4f5
7
+ data.tar.gz: 858d05b38816d4d99768985bf0ad16ebc82dd51309f1e5444ff2ce475e501e038b50e4b017dc1f2c16126e20eaafe32a999f85d835fe7f996b13765238be1135
@@ -91,10 +91,3 @@ Feature: Running the binary unsuccessfully
91
91
  def m() m end # ~> SystemStackError: stack level too deep
92
92
  m
93
93
  """
94
-
95
- Scenario: Total Fucking Failure
96
- Given the file "sib_will_utterly_die.rb" "__TOTAL_FUCKING_FAILURE__"
97
- When I run "seeing_is_believing sib_will_utterly_die.rb"
98
- Then stderr is not empty
99
- And the exit status is 2
100
- And stdout is empty
@@ -385,7 +385,7 @@ Feature: Using flags
385
385
  Scenario: --inherit-exit-status in an at_exit block
386
386
  Given the file "exit_status_in_at_exit_block.rb" "at_exit { exit 10 }"
387
387
  When I run "seeing_is_believing exit_status_in_at_exit_block.rb"
388
- Then the exit status is 0
388
+ Then the exit status is 1
389
389
  When I run "seeing_is_believing --inherit-exit-status exit_status_in_at_exit_block.rb"
390
390
  Then the exit status is 10
391
391
 
@@ -344,6 +344,7 @@ Feature:
344
344
  # !> stderr gets past it b/c of dumb ruby bug
345
345
  """
346
346
 
347
+
347
348
  Scenario: Incorrect wrapping in some programs
348
349
  Given the file "incorrect_wrapping.rb":
349
350
  """
@@ -391,3 +392,25 @@ Feature:
391
392
  end # => {{method_result :!}}
392
393
  end
393
394
  """
395
+
396
+
397
+ Scenario: Is cool with exceptions raised in at_exit hooks
398
+ Given the file "at_exit_exception_direct.rb" "at_exit { raise 'zomg' }"
399
+ When I run "seeing_is_believing at_exit_exception_direct.rb"
400
+ Then stderr is empty
401
+ And the exit status is 1
402
+ And stdout includes "at_exit { raise 'zomg' } # ~>"
403
+ And stdout includes "RuntimeError"
404
+ And stdout includes "zomg"
405
+ And stdout does not include "the_matrix"
406
+
407
+
408
+ Scenario: Is cool with exceptions raised in at_exit exceptions by code not in the running file (e.g. SimpleCov)
409
+ Given the file "at_exit_exception_indirect1.rb" "at_exit { raise 'zomg' }"
410
+ Given the file "at_exit_exception_indirect2.rb" "require_relative 'at_exit_exception_indirect1'"
411
+ When I run "seeing_is_believing at_exit_exception_indirect2.rb"
412
+ Then stderr is empty
413
+ And the exit status is 1
414
+ And stdout includes "require_relative 'at_exit_exception_indirect1' # => true"
415
+ And stdout includes "RuntimeError"
416
+ And stdout includes "zomg"
@@ -30,31 +30,12 @@ class SeeingIsBelieving
30
30
  end
31
31
 
32
32
  def call
33
- @memoized_result ||= begin
34
- new_program = program_that_will_record_expressions
33
+ @memoized_result ||= Dir.mktmpdir("seeing_is_believing_temp_dir") { |dir|
34
+ filename = @filename || File.join(dir, 'program.rb')
35
+ new_program = @record_expressions.call "#{@program.chomp}\n", filename, @number_of_captures
35
36
  @debugger.context("TRANSLATED PROGRAM") { new_program }
36
- result = result_for new_program
37
- @debugger.context("RESULT") { result.inspect }
38
- result
39
- end
40
- end
41
-
42
- private
43
-
44
- def to_stream(string_or_stream)
45
- return string_or_stream if string_or_stream.respond_to? :gets
46
- StringIO.new string_or_stream
47
- end
48
-
49
- def program_that_will_record_expressions
50
- @record_expressions.call "#{@program.chomp}\n", @number_of_captures
51
- end
52
37
 
53
- def result_for(program)
54
- Dir.mktmpdir "seeing_is_believing_temp_dir" do |dir|
55
- filename = @filename || File.join(dir, 'program.rb')
56
-
57
- @evaluator.call program,
38
+ result = @evaluator.call new_program,
58
39
  filename,
59
40
  input_stream: @stdin,
60
41
  require: @require,
@@ -63,6 +44,17 @@ class SeeingIsBelieving
63
44
  timeout: @timeout,
64
45
  ruby_executable: @ruby_executable,
65
46
  debugger: @debugger
66
- end
47
+
48
+ @debugger.context("RESULT") { result.inspect }
49
+
50
+ result
51
+ }
52
+ end
53
+
54
+ private
55
+
56
+ def to_stream(string_or_stream)
57
+ return string_or_stream if string_or_stream.respond_to? :gets
58
+ StringIO.new string_or_stream
67
59
  end
68
60
  end
@@ -79,7 +79,7 @@ class SeeingIsBelieving
79
79
 
80
80
  if options.inherit_exit_status?
81
81
  results.exitstatus
82
- elsif results.has_exception?
82
+ elsif results.has_exception? && results.exitstatus != 0 # e.g. `exit 0` raises SystemExit but isn't an error
83
83
  DISPLAYABLE_ERROR_STATUS
84
84
  else
85
85
  SUCCESS_STATUS
@@ -9,7 +9,7 @@ class SeeingIsBelieving
9
9
  end
10
10
 
11
11
  def self.expression_wrapper(markers, marker_regexes)
12
- -> program, number_of_captures {
12
+ lambda do |program, filename, number_of_captures|
13
13
  inspect_linenos = []
14
14
  pp_linenos = []
15
15
  Code.new(program).inline_comments.each do |c|
@@ -19,12 +19,13 @@ class SeeingIsBelieving
19
19
  end
20
20
 
21
21
  InspectExpressions.call program,
22
+ filename,
22
23
  number_of_captures,
23
24
  before_all: -> {
24
25
  # TODO: this is duplicated with the InspectExpressions class
25
26
  number_of_captures_as_str = number_of_captures.inspect
26
27
  number_of_captures_as_str = 'Float::INFINITY' if number_of_captures == Float::INFINITY
27
- "begin; require 'pp'; $SiB.max_line_captures = #{number_of_captures_as_str}; $SiB.num_lines = #{program.lines.count}; "
28
+ "require 'pp'; $SiB.filename = #{filename.inspect}; $SiB.max_line_captures = #{number_of_captures_as_str}; $SiB.num_lines = #{program.lines.count}; "
28
29
  },
29
30
  after_each: -> line_number {
30
31
  should_inspect = inspect_linenos.include?(line_number)
@@ -38,7 +39,7 @@ class SeeingIsBelieving
38
39
  else ")"
39
40
  end
40
41
  }
41
- }
42
+ end
42
43
  end
43
44
 
44
45
  def self.call(body, results, options)
@@ -24,7 +24,6 @@ require 'seeing_is_believing/event_stream/update_result'
24
24
 
25
25
  class SeeingIsBelieving
26
26
  class EvaluateByMovingFiles
27
-
28
27
  def self.call(*args)
29
28
  new(*args).call
30
29
  end
@@ -51,10 +50,9 @@ class SeeingIsBelieving
51
50
  write_program_to_file
52
51
  begin
53
52
  evaluate_file
54
- fail if result.bug_in_sib?
55
53
  result
56
54
  rescue Exception => error
57
- error = wrap_error error if error_implies_bug_in_sib? error
55
+ error = wrap_error error unless error.kind_of? Timeout::Error
58
56
  raise error
59
57
  end
60
58
  },
@@ -75,10 +73,6 @@ class SeeingIsBelieving
75
73
 
76
74
  attr_accessor :stdout, :stderr, :exitstatus
77
75
 
78
- def error_implies_bug_in_sib?(error)
79
- not error.kind_of? Timeout::Error
80
- end
81
-
82
76
  def we_will_not_overwrite_existing_tempfile!
83
77
  raise TempFileAlreadyExists.new(filename, temp_filename) if File.exist? temp_filename
84
78
  end
@@ -110,7 +104,7 @@ class SeeingIsBelieving
110
104
  }
111
105
 
112
106
  # consume events
113
- self.result = Result.new
107
+ self.result = Result.new # set on self b/c if an error is raised, we still want to keep what we recorded
114
108
  event_consumer = Thread.new do
115
109
  EventStream::Consumer.new(process_stdout)
116
110
  .each { |event| EventStream::UpdateResult.call result, event }
@@ -89,8 +89,6 @@ class SeeingIsBelieving
89
89
  Events::Stdout.new(extract_string line)
90
90
  when :stderr
91
91
  Events::Stderr.new(extract_string line)
92
- when :bug_in_sib
93
- Events::BugInSiB.new(extract_token(line) == 'true')
94
92
  when :max_line_captures
95
93
  token = extract_token(line)
96
94
  value = token =~ /infinity/i ? Float::INFINITY : token.to_i
@@ -5,7 +5,6 @@ class SeeingIsBelieving
5
5
  UnrecordedResult = Struct.new(:type, :line_number)
6
6
  Stdout = Struct.new(:value)
7
7
  Stderr = Struct.new(:value)
8
- BugInSiB = Struct.new(:value)
9
8
  MaxLineCaptures = Struct.new(:value)
10
9
  NumLines = Struct.new(:value)
11
10
  Exitstatus = Struct.new(:value)
@@ -3,11 +3,11 @@ class SeeingIsBelieving
3
3
  module EventStream
4
4
  require 'thread'
5
5
  class Producer
6
- attr_accessor :exitstatus, :bug_in_sib, :max_line_captures, :num_lines
6
+ attr_accessor :exitstatus, :max_line_captures, :num_lines, :filename
7
7
 
8
8
  def initialize(resultstream)
9
+ self.filename = nil
9
10
  self.exitstatus = 0
10
- self.bug_in_sib = false
11
11
  self.max_line_captures = Float::INFINITY
12
12
  self.num_lines = 0
13
13
  self.recorded_results = []
@@ -15,6 +15,7 @@ class SeeingIsBelieving
15
15
  self.producer_thread = Thread.new do
16
16
  finish = "finish"
17
17
  begin
18
+ resultstream.sync = true
18
19
  loop do
19
20
  to_publish = queue.shift
20
21
  if to_publish == finish
@@ -26,14 +27,12 @@ class SeeingIsBelieving
26
27
  end
27
28
  rescue IOError, Errno::EPIPE
28
29
  loop { break if queue.shift == finish }
30
+ ensure
31
+ resultstream.flush rescue nil
29
32
  end
30
33
  end
31
34
  end
32
35
 
33
- def bug_in_sib=(bool)
34
- @bug_in_sib = (bool ? true : false)
35
- end
36
-
37
36
  # for a consideration of many different ways of doing this, see 5633064
38
37
  def to_string_token(string)
39
38
  [Marshal.dump(string.to_s)].pack('m0')
@@ -70,7 +69,16 @@ class SeeingIsBelieving
70
69
  end
71
70
 
72
71
  def record_exception(line_number, exception)
73
- self.num_lines = line_number if num_lines < line_number
72
+ self.exitstatus = (exception.kind_of?(SystemExit) ? exception.status : 1)
73
+ if line_number
74
+ self.num_lines = line_number if num_lines < line_number
75
+ elsif filename
76
+ begin
77
+ line_number = exception.backtrace.grep(/#{filename}/).first[/:\d+/][1..-1].to_i
78
+ rescue Exception
79
+ end
80
+ end
81
+ line_number ||= -1
74
82
  queue << "exception"
75
83
  queue << " line_number #{line_number}"
76
84
  queue << " class_name #{to_string_token exception.class.name}"
@@ -90,7 +98,6 @@ class SeeingIsBelieving
90
98
  end
91
99
 
92
100
  def finish!
93
- queue << "bug_in_sib #{bug_in_sib}"
94
101
  queue << "max_line_captures #{max_line_captures}"
95
102
  queue << "num_lines #{num_lines}"
96
103
  queue << "exitstatus #{exitstatus}"
@@ -9,7 +9,6 @@ class SeeingIsBelieving
9
9
  when EventStream::Events::Exception then result.record_exception event.line_number, event.class_name, event.message, event.backtrace
10
10
  when EventStream::Events::Stdout then result.stdout = event.value
11
11
  when EventStream::Events::Stderr then result.stderr = event.value
12
- when EventStream::Events::BugInSiB then result.bug_in_sib = event.value
13
12
  when EventStream::Events::MaxLineCaptures then result.number_of_captures = event.value
14
13
  when EventStream::Events::Exitstatus then result.exitstatus = event.value
15
14
  when EventStream::Events::NumLines then result.num_lines = event.value
@@ -1,21 +1,14 @@
1
1
  require 'seeing_is_believing/wrap_expressions'
2
2
  class SeeingIsBelieving
3
3
  module InspectExpressions
4
- def self.call(program, number_of_captures, options={})
4
+ def self.call(program, filename, number_of_captures, options={})
5
+ # TODO: much of this is duplicated in annotate_xmpfilter_stle
5
6
  number_of_captures_as_str = number_of_captures.inspect
6
7
  number_of_captures_as_str = 'Float::INFINITY' if number_of_captures == Float::INFINITY
7
8
 
8
9
  wrap_expressions_callbacks = {}
9
- wrap_expressions_callbacks[:before_all] = options.fetch :before_all, -> { "begin; $SiB.max_line_captures = #{number_of_captures_as_str}; $SiB.num_lines = #{program.lines.count}; " }
10
- wrap_expressions_callbacks[:after_all] = options.fetch :after_all, -> { ";rescue Exception;"\
11
- "lambda {"\
12
- "line_number = $!.backtrace.grep(/\#{__FILE__}/).first[/:\\d+/][1..-1].to_i;"\
13
- "$SiB.record_exception line_number, $!;"\
14
- "$SiB.exitstatus = 1;"\
15
- "$SiB.exitstatus = $!.status if $!.kind_of? SystemExit;"\
16
- "}.call;"\
17
- "end"
18
- }
10
+ wrap_expressions_callbacks[:before_all] = options.fetch :before_all, -> { "$SiB.filename = #{filename.inspect}; $SiB.max_line_captures = #{number_of_captures_as_str}; $SiB.num_lines = #{program.lines.count}; " }
11
+ wrap_expressions_callbacks[:after_all] = options.fetch :after_all, -> { "" }
19
12
  wrap_expressions_callbacks[:before_each] = options.fetch :before_each, -> line_number { "(" }
20
13
  wrap_expressions_callbacks[:after_each] = options.fetch :after_each, -> line_number { ").tap { |v| $SiB.record_result(:inspect, #{line_number}, v) }" }
21
14
  WrapExpressions.call program, wrap_expressions_callbacks
@@ -3,10 +3,9 @@ class SeeingIsBelieving
3
3
  include Enumerable
4
4
  RecordedException = Struct.new :line_number, :class_name, :message, :backtrace
5
5
 
6
- attr_accessor :stdout, :stderr, :exitstatus, :bug_in_sib, :number_of_captures, :exception, :num_lines
6
+ attr_accessor :stdout, :stderr, :exitstatus, :number_of_captures, :exception, :num_lines
7
7
 
8
8
  alias has_exception? exception
9
- alias bug_in_sib? bug_in_sib
10
9
 
11
10
  def has_stdout?
12
11
  stdout && !stdout.empty?
@@ -8,33 +8,28 @@
8
8
  require_relative 'version'
9
9
  require_relative 'event_stream/producer'
10
10
 
11
- stdout_real_obj = STDOUT # the real Ruby object, fake file descriptor
12
- stdout_real_fd = STDOUT.dup # duped Ruby object, real file descriptor
13
- read_from_mock_out, write_to_mock_out = IO.pipe
14
- stdout_real_obj.reopen write_to_mock_out
11
+ event_stream = STDOUT.dup # duped Ruby object with the real file descriptor
12
+ $SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
15
13
 
16
- stderr_real_obj = STDERR
17
- stderr_real_fd = STDERR.dup
18
- read_from_mock_err, write_to_mock_err = IO.pipe
19
- stderr_real_obj.reopen write_to_mock_err
14
+ stdout = STDOUT # keep our own ref, b/c user could mess w/ constants and globals
15
+ read_stdout, write_stdout = IO.pipe
16
+ stdout.reopen(write_stdout)
20
17
 
21
- $SiB = SeeingIsBelieving::EventStream::Producer.new(stdout_real_fd)
18
+ stderr = STDERR
19
+ read_stderr, write_stderr = IO.pipe
20
+ stderr.reopen(write_stderr)
22
21
 
23
22
  at_exit do
24
- stdout_real_obj.reopen stdout_real_fd
25
- write_to_mock_out.close unless write_to_mock_out.closed?
26
- $SiB.record_stdout read_from_mock_out.read
27
- read_from_mock_out.close
23
+ _, blackhole = IO.pipe
24
+ stdout.reopen(blackhole)
25
+ stderr.reopen(blackhole)
28
26
 
29
- stderr_real_obj.reopen stderr_real_fd
30
- write_to_mock_err.close unless write_to_mock_err.closed?
31
- $SiB.record_stderr read_from_mock_err.read
32
- read_from_mock_err.close
27
+ write_stdout.close unless write_stdout.closed?
28
+ $SiB.record_stdout read_stdout.read
33
29
 
34
- $SiB.exitstatus ||= 0
35
- $SiB.exitstatus = 1 if $!
36
- $SiB.exitstatus = $!.status if $!.kind_of? SystemExit
37
- $SiB.bug_in_sib = $! && ! $!.kind_of?(SystemExit)
30
+ write_stderr.close unless write_stderr.closed?
31
+ $SiB.record_stderr read_stderr.read
38
32
 
33
+ $SiB.record_exception nil, $! if $!
39
34
  $SiB.finish!
40
35
  end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '3.0.0.beta.2'
2
+ VERSION = '3.0.0.beta.3'
3
3
  end
@@ -101,7 +101,7 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
101
101
  expect(result.stdout).to eq "123\n"
102
102
  end
103
103
 
104
- it 'will set the encoding' do
104
+ it 'can set the encoding' do
105
105
  test = -> { expect(invoke('print "ç"', encoding: 'u').stdout).to eq "ç" }
106
106
  if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
107
107
  pending "Rubinius doesn't seem to use -Kx, but rather -U"
@@ -111,11 +111,16 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
111
111
  end
112
112
  end
113
113
 
114
- it 'if it fails, it prints some debugging information and raises an error' do
114
+ it 'if it fails, it tells the debugger some information and raises an error' do
115
115
  error_stream = StringIO.new
116
116
  evaluator = described_class.new 'raise "omg"', filename, debugger: SeeingIsBelieving::Debugger.new(stream: error_stream)
117
+ expect(evaluator).to receive(:evaluate_file).and_raise("whatevz")
117
118
  FileUtils.rm_f evaluator.temp_filename
118
119
  expect { evaluator.call }.to raise_error SeeingIsBelieving::BugInSib
119
120
  expect(error_stream.string).to include "Program could not be evaluated"
120
121
  end
122
+
123
+ it 'does not blow up on exceptions raised in at_exit blocks' do
124
+ expect { invoke 'at_exit { raise "zomg" }' }.to_not raise_error
125
+ end
121
126
  end
@@ -58,7 +58,7 @@ module SeeingIsBelieving::EventStream
58
58
 
59
59
  it 'raises NoMoreInput and marks itself finished once it receives the finish event' do
60
60
  producer.finish!
61
- consumer.call 5
61
+ consumer.call 4
62
62
  expect { consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::NoMoreInput
63
63
  expect(consumer).to be_finished
64
64
  end
@@ -258,37 +258,118 @@ module SeeingIsBelieving::EventStream
258
258
  end
259
259
 
260
260
  describe 'exceptions' do
261
- def assert_exception(recorded_exception, recorded_line_no, class_name, message_matcher, backtrace_index, backtrace_line)
261
+ def record_exception(linenum=nil, &raises_exception)
262
+ raises_exception.call
263
+ rescue Exception
264
+ producer.record_exception linenum, $!
265
+ return raises_exception.source_location.last
266
+ end
267
+
268
+ def assert_exception(recorded_exception, options={})
262
269
  expect(recorded_exception).to be_a_kind_of Events::Exception
263
- expect(recorded_exception.line_number).to eq recorded_line_no
264
- expect(recorded_exception.class_name).to eq class_name
265
- expect(recorded_exception.message).to match message_matcher
270
+ expect(recorded_exception.line_number).to eq options[:recorded_line_no]
271
+ expect(recorded_exception.class_name ).to match options[:class_name_matcher] if options[:class_name_matcher]
272
+ expect(recorded_exception.message ).to match options[:message_matcher] if options[:message_matcher]
266
273
 
267
274
  backtrace = recorded_exception.backtrace
268
275
  expect(backtrace).to be_a_kind_of Array
269
276
  expect(backtrace).to be_all { |frame| String === frame }
270
- frame = backtrace[backtrace_index]
271
- expect(frame).to match __FILE__
272
- expect(frame).to match /\b#{backtrace_line}\b/
277
+ frame = backtrace[options[:backtrace_index]||0]
278
+ expect(frame).to match /(^|\b)#{options[:backtrace_filename]}(\b|$)/ if options[:backtrace_filename]
279
+ expect(frame).to match /(^|\b)#{options[:backtrace_line]}(\b|$)/ if options[:backtrace_line]
273
280
  end
274
281
 
275
282
  it 'emits the line_number, an escaped class_name, an escaped message, and escaped backtrace' do
276
- begin
277
- raise ZeroDivisionError, 'omg'
278
- rescue
279
- producer.record_exception 12, $!
280
- end
281
- assert_exception consumer.call, 12, 'ZeroDivisionError', /\Aomg\Z/, 0, __LINE__-4
283
+ backtrace_line = record_exception(12) { raise ZeroDivisionError, 'omg' }
284
+ assert_exception consumer.call,
285
+ recorded_line_no: 12,
286
+ class_name_matcher: /^ZeroDivisionError$/,
287
+ message_matcher: /\Aomg\Z/,
288
+ backtrace_index: 0,
289
+ backtrace_line: backtrace_line,
290
+ backtrace_filename: __FILE__
282
291
  end
283
292
 
284
293
  example 'Example: Common edge case: name error' do
285
- begin
286
- not_a_local_or_meth
287
- rescue
288
- producer.record_exception 99, $!
294
+ backtrace_line = record_exception(99) { not_a_local_or_meth }
295
+ backtrace_frame = 1 # b/c this one will get caught by rspec's method missing
296
+ assert_exception consumer.call,
297
+ recorded_line_no: 99,
298
+ class_name_matcher: /^NameError$/,
299
+ message_matcher: /\bnot_a_local_or_meth\b/,
300
+ backtrace_index: 1,
301
+ backtrace_line: backtrace_line,
302
+ backtrace_filename: __FILE__
303
+ end
304
+
305
+ context 'when the exception is a SystemExit' do
306
+ it 'sets the exit status to the one provided' do
307
+ record_exception { exit 22 }
308
+ expect(producer.exitstatus).to eq 22
309
+ end
310
+
311
+ it 'sets the exit status to 0 or 1 if exited with true or false' do
312
+ expect(producer.exitstatus).to eq 0
313
+ record_exception { exit true }
314
+ expect(producer.exitstatus).to eq 0
315
+ record_exception { exit false }
316
+ expect(producer.exitstatus).to eq 1
317
+ end
318
+
319
+ it 'sets the exit status to 1 if the exception is not a SystemExit' do
320
+ expect(producer.exitstatus).to eq 0
321
+ record_exception { raise }
322
+ expect(producer.exitstatus).to eq 1
323
+ end
324
+ end
325
+
326
+ context 'recorded line number | line num is provided | it knows the file | exception comes from within file' do
327
+ let(:exception) { begin; raise "zomg"; rescue; $!; end }
328
+ let(:linenum) { __LINE__ - 1 }
329
+ it "provided one | true | true | true" do
330
+ producer.filename = __FILE__
331
+ producer.record_exception 12, exception
332
+ assert_exception consumer.call, recorded_line_no: 12
333
+ end
334
+ it "provided one | true | true | false" do
335
+ exception.backtrace.replace ['otherfile.rb']
336
+ producer.record_exception 12, exception
337
+ producer.filename = __FILE__
338
+ assert_exception consumer.call, recorded_line_no: 12
339
+ end
340
+ it "provided one | true | false | true" do
341
+ producer.filename = nil
342
+ producer.record_exception 12, exception
343
+ assert_exception consumer.call, recorded_line_no: 12
344
+ end
345
+ it "provided one | true | false | false" do
346
+ exception.backtrace.replace ['otherfile.rb']
347
+ producer.filename = nil
348
+ producer.record_exception 12, exception
349
+ assert_exception consumer.call, recorded_line_no: 12
350
+ end
351
+ it "from backtrace | false | true | true" do
352
+ producer.filename = __FILE__
353
+ producer.record_exception nil, exception
354
+ assert_exception consumer.call, recorded_line_no: linenum
355
+ end
356
+ it "-1 | false | true | false" do
357
+ exception.backtrace.replace ['otherfile.rb']
358
+ producer.filename = __FILE__
359
+ producer.record_exception nil, exception
360
+ assert_exception consumer.call, recorded_line_no: -1
361
+ end
362
+ it "-1 | false | false | true" do
363
+ producer.filename = nil
364
+ producer.record_exception nil, exception
365
+ assert_exception consumer.call, recorded_line_no: -1
366
+ end
367
+ it "-1 | false | false | false" do
368
+ exception.backtrace.replace ['otherfile.rb']
369
+ producer.filename = nil
370
+ producer.record_exception nil, exception
371
+ assert_exception consumer.call, recorded_line_no: -1
289
372
  end
290
- backtrace_frame = 1 # b/c this one will get caught by method missing
291
- assert_exception consumer.call, 99, 'NameError', /\bnot_a_local_or_meth\b/, 1, __LINE__-5
292
373
  end
293
374
  end
294
375
 
@@ -309,23 +390,7 @@ module SeeingIsBelieving::EventStream
309
390
  describe 'finish!' do
310
391
  def final_event(producer, consumer, event_class)
311
392
  producer.finish!
312
- consumer.call(5).find { |e| e.class == event_class }
313
- end
314
-
315
- describe 'bug_in_sib' do
316
- it 'truthy values are transated to true' do
317
- producer.bug_in_sib = 'a value'
318
- expect(final_event(producer, consumer, Events::BugInSiB).value).to equal true
319
- end
320
-
321
- it 'falsy values are translated to false' do
322
- producer.bug_in_sib = nil
323
- expect(final_event(producer, consumer, Events::BugInSiB).value).to equal false
324
- end
325
-
326
- it 'is false by default, and is always emitted' do
327
- expect(final_event(producer, consumer, Events::BugInSiB).value).to equal false
328
- end
393
+ consumer.call(4).find { |e| e.class == event_class }
329
394
  end
330
395
 
331
396
  describe 'max_line_captures' do
@@ -356,15 +421,15 @@ module SeeingIsBelieving::EventStream
356
421
 
357
422
  it 'updates its value if it sees a result from a line larger than its value' do
358
423
  producer.num_lines = 2
359
- producer.record_result :sometype, 5, :someval
360
- expect(final_event(producer, consumer, Events::NumLines).value).to eq 5
424
+ producer.record_result :sometype, 100, :someval
425
+ expect(final_event(producer, consumer, Events::NumLines).value).to eq 100
361
426
  end
362
427
 
363
428
  it 'updates its value if it sees an exception from a line larger than its value' do
364
429
  producer.num_lines = 2
365
430
  begin; raise; rescue; e = $!; end
366
- producer.record_exception 5, e
367
- expect(final_event(producer, consumer, Events::NumLines).value).to eq 5
431
+ producer.record_exception 100, e
432
+ expect(final_event(producer, consumer, Events::NumLines).value).to eq 100
368
433
  end
369
434
  end
370
435
 
@@ -46,9 +46,10 @@ RSpec.describe SeeingIsBelieving do
46
46
  end
47
47
 
48
48
  it 'allows uers to pass in their own inspection recorder' do
49
- wrapper = lambda { |program, num_captures|
49
+ wrapper = lambda { |program, filename, num_captures|
50
50
  SeeingIsBelieving::InspectExpressions.call \
51
51
  program,
52
+ filename,
52
53
  num_captures,
53
54
  after_each: -> line_number { ").tap { $SiB.record_result(:inspect, #{line_number}, 'zomg') }" }
54
55
  }
@@ -144,6 +145,30 @@ RSpec.describe SeeingIsBelieving do
144
145
  expect(result.exception.backtrace).to be_a_kind_of Array
145
146
  end
146
147
 
148
+ context 'exceptions in exit blocks', t:true do
149
+ # I'm punting on this because there is just no good way to stop that from happening without changing actual behaviour
150
+ # see https://github.com/JoshCheek/seeing_is_believing/issues/24
151
+ it 'does not include information about the_matrix in the exception backtraces' do
152
+ result1 = invoke("raise Exception, 'something'")
153
+ result2 = invoke("at_exit { raise Exception, 'something' }")
154
+ result1.exception.backtrace.each { |line| expect(line).to_not match /the_matrix/ }
155
+ result2.exception.backtrace.each { |line| expect(line).to_not match /the_matrix/ }
156
+ end
157
+
158
+ it 'can print in at_exit hooks' do
159
+ result = invoke("at_exit { $stderr.print 'err output'; $stdout.print 'out output' }")
160
+ expect(result.stderr).to eq 'err output'
161
+ expect(result.stdout).to eq 'out output'
162
+ end
163
+
164
+ it 'can see previous hooks exceptions' do
165
+ result = invoke("at_exit { puts $!.message.reverse}; at_exit { raise 'reverse this' }")
166
+ expect(result.stdout).to eq "siht esrever\n"
167
+ end
168
+ end
169
+
170
+
171
+
147
172
  it 'does not fuck up __LINE__ macro' do
148
173
  expect(values_for( '__LINE__
149
174
  __LINE__
@@ -444,7 +469,7 @@ RSpec.describe SeeingIsBelieving do
444
469
  it 'prints the pre-evaluated program' do
445
470
  call
446
471
  expect(stream.string).to include "TRANSLATED PROGRAM:"
447
- expect(stream.string).to include "\nbegin;" # there is more, but we're just interested in showing that it wound up in the stream
472
+ expect(stream.string).to include "$SiB.num_lines" # there is more, but we're just interested in showing that it wound up in the stream
448
473
  end
449
474
 
450
475
  it 'prints the result' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seeing_is_believing
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.beta.2
4
+ version: 3.0.0.beta.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Cheek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-27 00:00:00.000000000 Z
11
+ date: 2014-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eval_in
@@ -267,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
267
  version: 1.3.1
268
268
  requirements: []
269
269
  rubyforge_project: seeing_is_believing
270
- rubygems_version: 2.0.14
270
+ rubygems_version: 2.4.1
271
271
  signing_key:
272
272
  specification_version: 4
273
273
  summary: Records results of every line of code in your file
@@ -293,3 +293,4 @@ test_files:
293
293
  - spec/seeing_is_believing_spec.rb
294
294
  - spec/spec_helper.rb
295
295
  - spec/wrap_expressions_spec.rb
296
+ has_rdoc: