seeing_is_believing 3.0.0.beta.2 → 3.0.0.beta.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: 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: