seeing_is_believing 3.0.0.beta.3 → 3.0.0.beta.4

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.
@@ -6,10 +6,12 @@ class SeeingIsBelieving
6
6
  Stdout = Struct.new(:value)
7
7
  Stderr = Struct.new(:value)
8
8
  MaxLineCaptures = Struct.new(:value)
9
+ Filename = Struct.new(:value)
9
10
  NumLines = Struct.new(:value)
11
+ SiBVersion = Struct.new(:value)
12
+ RubyVersion = Struct.new(:value)
10
13
  Exitstatus = Struct.new(:value)
11
14
  Exception = Struct.new(:line_number, :class_name, :message, :backtrace)
12
- Finish = Class.new
13
15
  end
14
16
  end
15
17
  end
@@ -1,8 +1,16 @@
1
1
  require 'seeing_is_believing/event_stream/events'
2
+ require 'thread'
3
+
2
4
  class SeeingIsBelieving
3
5
  module EventStream
4
- require 'thread'
5
6
  class Producer
7
+
8
+ module NullQueue
9
+ extend self
10
+ def <<(*) end
11
+ def shift() end
12
+ end
13
+
6
14
  attr_accessor :exitstatus, :max_line_captures, :num_lines, :filename
7
15
 
8
16
  def initialize(resultstream)
@@ -11,31 +19,38 @@ class SeeingIsBelieving
11
19
  self.max_line_captures = Float::INFINITY
12
20
  self.num_lines = 0
13
21
  self.recorded_results = []
14
- self.queue = Thread::Queue.new
22
+ self.queue = Queue.new
15
23
  self.producer_thread = Thread.new do
16
- finish = "finish"
17
24
  begin
18
25
  resultstream.sync = true
19
26
  loop do
20
27
  to_publish = queue.shift
21
- if to_publish == finish
22
- resultstream << "finish\n"
23
- break
24
- else
25
- resultstream << (to_publish << "\n")
26
- end
28
+ break if to_publish == :break
29
+ resultstream << (to_publish << "\n")
27
30
  end
28
31
  rescue IOError, Errno::EPIPE
29
- loop { break if queue.shift == finish }
32
+ queue.clear
30
33
  ensure
31
34
  resultstream.flush rescue nil
32
35
  end
36
+ self.queue = NullQueue
33
37
  end
34
38
  end
35
39
 
36
- # for a consideration of many different ways of doing this, see 5633064
37
- def to_string_token(string)
38
- [Marshal.dump(string.to_s)].pack('m0')
40
+ attr_reader :version
41
+ alias ver version
42
+ def record_sib_version(sib_version)
43
+ @version = sib_version
44
+ queue << "sib_version #{to_string_token sib_version}"
45
+ end
46
+
47
+ def record_ruby_version(ruby_version)
48
+ queue << "ruby_version #{to_string_token ruby_version}"
49
+ end
50
+
51
+ def record_max_line_captures(max_line_captures)
52
+ self.max_line_captures = max_line_captures
53
+ queue << "max_line_captures #{max_line_captures}"
39
54
  end
40
55
 
41
56
  StackErrors = [SystemStackError]
@@ -89,25 +104,27 @@ class SeeingIsBelieving
89
104
  queue << "end"
90
105
  end
91
106
 
92
- def record_stdout(stdout)
93
- queue << "stdout #{to_string_token stdout}"
94
- end
95
-
96
- def record_stderr(stderr)
97
- queue << "stderr #{to_string_token stderr}"
107
+ def record_filename(filename)
108
+ self.filename = filename
109
+ queue << "filename #{to_string_token filename}"
98
110
  end
99
111
 
112
+ # note that producer will continue reading until stream is closed
100
113
  def finish!
101
- queue << "max_line_captures #{max_line_captures}"
102
114
  queue << "num_lines #{num_lines}"
103
115
  queue << "exitstatus #{exitstatus}"
104
- queue << "finish".freeze
116
+ queue << :break
105
117
  producer_thread.join
106
118
  end
107
119
 
108
120
  private
109
121
 
110
122
  attr_accessor :resultstream, :queue, :producer_thread, :recorded_results
123
+
124
+ # for a consideration of many different ways of doing this, see 5633064
125
+ def to_string_token(string)
126
+ [Marshal.dump(string.to_s)].pack('m0')
127
+ end
111
128
  end
112
129
  end
113
130
  end
@@ -1,17 +1,21 @@
1
1
  require 'seeing_is_believing/event_stream/events'
2
2
  class SeeingIsBelieving
3
3
  module EventStream
4
+ # Adapter between EventStream and Result
4
5
  module UpdateResult
5
6
  def self.call(result, event)
6
7
  case event
7
8
  when EventStream::Events::LineResult then result.record_result(event.type, event.line_number, event.inspected)
8
9
  when EventStream::Events::UnrecordedResult then result.record_result(event.type, event.line_number, '...') # <-- is this really what I want?
9
10
  when EventStream::Events::Exception then result.record_exception event.line_number, event.class_name, event.message, event.backtrace
10
- when EventStream::Events::Stdout then result.stdout = event.value
11
- when EventStream::Events::Stderr then result.stderr = event.value
11
+ when EventStream::Events::Stdout then result.stdout << event.value
12
+ when EventStream::Events::Stderr then result.stderr << event.value
12
13
  when EventStream::Events::MaxLineCaptures then result.number_of_captures = event.value
13
14
  when EventStream::Events::Exitstatus then result.exitstatus = event.value
14
15
  when EventStream::Events::NumLines then result.num_lines = event.value
16
+ when EventStream::Events::SiBVersion then result.sib_version = event.value
17
+ when EventStream::Events::RubyVersion then result.ruby_version = event.value
18
+ when EventStream::Events::Filename then result.filename = event.value
15
19
  else raise "Unknown event: #{event.inspect}"
16
20
  end
17
21
  end
@@ -7,7 +7,11 @@ class SeeingIsBelieving
7
7
  number_of_captures_as_str = 'Float::INFINITY' if number_of_captures == Float::INFINITY
8
8
 
9
9
  wrap_expressions_callbacks = {}
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}; " }
10
+ wrap_expressions_callbacks[:before_all] = options.fetch :before_all, -> { "$SiB.record_ruby_version RUBY_VERSION;"\
11
+ "$SiB.record_sib_version #{VERSION.inspect};"\
12
+ "$SiB.record_filename #{filename.inspect};"\
13
+ "$SiB.record_max_line_captures #{number_of_captures_as_str};"\
14
+ "$SiB.num_lines = #{program.lines.count}; " }
11
15
  wrap_expressions_callbacks[:after_all] = options.fetch :after_all, -> { "" }
12
16
  wrap_expressions_callbacks[:before_each] = options.fetch :before_each, -> line_number { "(" }
13
17
  wrap_expressions_callbacks[:after_each] = options.fetch :after_each, -> line_number { ").tap { |v| $SiB.record_result(:inspect, #{line_number}, v) }" }
@@ -1,4 +1,14 @@
1
- require 'parser/current'
1
+ module Parser
2
+ class << self
3
+ # With new versioning, there's lots of small versions
4
+ # we don't need it to complain that we're on 2.1.1 and its parsing 2.1.5
5
+ # https://github.com/whitequark/parser/blob/e2249d7051b1adb6979139928e14a81bc62f566e/lib/parser/current.rb#L3
6
+ def warn(*) end
7
+ require 'parser/current'
8
+ remove_method :warn
9
+ end
10
+ end
11
+
2
12
  class SeeingIsBelieving
3
13
  module ParserHelpers
4
14
 
@@ -3,7 +3,12 @@ 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, :number_of_captures, :exception, :num_lines
6
+ attr_accessor :stdout, :stderr, :exitstatus, :number_of_captures, :exception, :num_lines, :sib_version, :ruby_version, :filename
7
+
8
+ def initialize
9
+ self.stdout = ''
10
+ self.stderr = ''
11
+ end
7
12
 
8
13
  alias has_exception? exception
9
14
 
@@ -8,28 +8,28 @@
8
8
  require_relative 'version'
9
9
  require_relative 'event_stream/producer'
10
10
 
11
- event_stream = STDOUT.dup # duped Ruby object with the real file descriptor
11
+ event_stream = IO.open(ARGV.shift.to_i, "w")
12
12
  $SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
13
13
 
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)
14
+ stdout, stderr = STDOUT, STDERR
15
+ finish = lambda do
16
+ $SiB.finish!
17
+ event_stream.close
18
+ stdout.flush
19
+ stderr.flush
20
+ end
17
21
 
18
- stderr = STDERR
19
- read_stderr, write_stderr = IO.pipe
20
- stderr.reopen(write_stderr)
22
+ real_exec = method :exec
23
+ Kernel.module_eval do
24
+ private
25
+ define_method :exec do |*args, &block| # TODO: Add an event for exec?
26
+ finish.call
27
+ real_exec.call(*args, &block)
28
+ end
29
+ end
21
30
 
22
31
  at_exit do
23
- _, blackhole = IO.pipe
24
- stdout.reopen(blackhole)
25
- stderr.reopen(blackhole)
26
-
27
- write_stdout.close unless write_stdout.closed?
28
- $SiB.record_stdout read_stdout.read
29
-
30
- write_stderr.close unless write_stderr.closed?
31
- $SiB.record_stderr read_stderr.read
32
-
33
32
  $SiB.record_exception nil, $! if $!
34
- $SiB.finish!
33
+ finish.call
34
+ Kernel.exit! 0 # clear the exception so it doesn't print to stderr and change the processes actual exit status (we recorded what it should be)
35
35
  end
@@ -1,3 +1,3 @@
1
1
  class SeeingIsBelieving
2
- VERSION = '3.0.0.beta.3'
2
+ VERSION = '3.0.0.beta.4'
3
3
  end
@@ -1,4 +1,3 @@
1
- require 'parser/current'
2
1
  require 'seeing_is_believing/parser_helpers'
3
2
 
4
3
  # comprehensive list of syntaxes that can come up
@@ -23,7 +23,6 @@ class SeeingIsBelieving
23
23
  @encoding = options.fetch :encoding, nil
24
24
  @timeout = options[:timeout]
25
25
  @debugger = options.fetch :debugger, Debugger.new(stream: nil)
26
- @ruby_executable = options.fetch :ruby_executable, 'ruby'
27
26
  @number_of_captures = options.fetch :number_of_captures, Float::INFINITY
28
27
  @evaluator = options.fetch :evaluator, EvaluateByMovingFiles
29
28
  @record_expressions = options.fetch :record_expressions, InspectExpressions # TODO: rename to wrap_expressions
@@ -42,7 +41,6 @@ class SeeingIsBelieving
42
41
  load_path: @load_path,
43
42
  encoding: @encoding,
44
43
  timeout: @timeout,
45
- ruby_executable: @ruby_executable,
46
44
  debugger: @debugger
47
45
 
48
46
  @debugger.context("RESULT") { result.inspect }
@@ -19,11 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_dependency "eval_in", "~> 0.1.6"
23
- s.add_dependency "parser", ">= 2.1.4", "< 2.3"
22
+ s.add_dependency "parser", ">= 2.2", "< 3.0"
24
23
 
25
- s.add_development_dependency "webmock", "~> 1.18"
26
- s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
24
+ s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
27
25
  s.add_development_dependency "rake", "~> 10.0"
28
26
  s.add_development_dependency "rspec", "~> 3.0"
29
27
  s.add_development_dependency "cucumber", "~> 1.2"
@@ -131,12 +131,6 @@ class SeeingIsBelieving
131
131
  end
132
132
  end
133
133
 
134
- context 'shebang' do
135
- it 'sets shebang to the value' do
136
- expect(call(shebang: 'whatevz').shebang).to eq 'whatevz'
137
- end
138
- end
139
-
140
134
  context 'filename' do
141
135
  it 'sets this as the filename' do
142
136
  expect(call(filename: 'somefilename').filename).to eq 'somefilename'
@@ -239,20 +233,12 @@ class SeeingIsBelieving
239
233
  expect(call[:evaluate_with]).to eq EvaluateByMovingFiles
240
234
  end
241
235
 
242
- specify 'evaluate_with is EvaluateWithEvalIn if safe is set' do
243
- expect(call(safe: true)[:evaluate_with]).to eq EvaluateWithEvalIn
244
- end
245
-
246
236
  specify 'filename is the as option or the provided filename' do
247
237
  expect(call(filename: 'from_fn')[:filename]).to eq 'from_fn'
248
238
  expect(call(as: 'from_as')[:filename]).to eq 'from_as'
249
239
  expect(call(as: 'from_as', filename: 'from_fn')[:filename]).to eq 'from_as'
250
240
  end
251
241
 
252
- specify 'ruby_executable is the shebang' do
253
- expect(call(shebang: 'shebangprog')[:ruby_executable]).to eq 'shebangprog'
254
- end
255
-
256
242
  specify 'stdin is empty when the program is on stdin, and is stdin otherwise' do
257
243
  # NOTE: the lib will normalize this into a stream
258
244
  expect(call(filename: nil, program_from_args: nil)[:stdin]).to eq ''
@@ -341,12 +341,11 @@ RSpec.describe SeeingIsBelieving::Binary::ParseArgs do
341
341
  end
342
342
 
343
343
  describe ':shebang' do
344
- it 'defaults to "ruby"' do
345
- expect(parse([])[:shebang]).to eq 'ruby'
346
- end
347
-
348
- it 'can be enabled with --shebang' do
349
- expect(parse(['--shebang', 'not_ruby'])[:shebang]).to eq 'not_ruby'
344
+ it 'is added to the list of deprecated flags' do
345
+ expect(parse([])[:deprecated_flags]).to eq []
346
+ parsed = parse(['--shebang', 'not_ruby', 'other'])
347
+ expect(parsed[:shebang]).to eq nil
348
+ expect(parsed[:deprecated_flags]).to eq ['--shebang', 'not_ruby']
350
349
  end
351
350
 
352
351
  it 'sets an error if not given a next arg to execute' do
@@ -5,28 +5,54 @@ require 'seeing_is_believing/event_stream/consumer'
5
5
 
6
6
  module SeeingIsBelieving::EventStream
7
7
  RSpec.describe SeeingIsBelieving::EventStream do
8
- attr_accessor :producer, :consumer, :readstream, :writestream
8
+ attr_accessor :producer, :consumer
9
+ attr_accessor :eventstream_consumer, :eventstream_producer
10
+ attr_accessor :stdout_consumer, :stdout_producer
11
+ attr_accessor :stderr_consumer, :stderr_producer
9
12
 
10
- before do
11
- self.readstream, self.writestream = IO.pipe
12
- self.producer = SeeingIsBelieving::EventStream::Producer.new(writestream)
13
- self.consumer = SeeingIsBelieving::EventStream::Consumer.new(readstream)
13
+ def close_streams(*streams)
14
+ streams.each { |fd| fd.close unless fd.closed? }
14
15
  end
15
16
 
16
- after {
17
+ def finish!
17
18
  producer.finish!
18
- readstream.close unless readstream.closed?
19
- writestream.close unless writestream.closed?
20
- }
19
+ close_streams eventstream_producer, stdout_producer, stderr_producer
20
+ end
21
+
22
+ before do
23
+ self.eventstream_consumer, self.eventstream_producer = IO.pipe
24
+ self.stdout_consumer, self.stdout_producer = IO.pipe
25
+ self.stderr_consumer, self.stderr_producer = IO.pipe
26
+
27
+ self.producer = SeeingIsBelieving::EventStream::Producer.new eventstream_producer
28
+ self.consumer = SeeingIsBelieving::EventStream::Consumer.new \
29
+ events: eventstream_consumer,
30
+ stdout: stdout_consumer,
31
+ stderr: stderr_consumer
32
+ end
33
+
34
+ after do
35
+ finish!
36
+ close_streams eventstream_consumer, stdout_consumer, stderr_consumer
37
+ end
21
38
 
22
39
  describe 'emitting an event' do
23
- # TODO: could not fucking figure out how to ask the goddam thing if it has data
24
- # read docs for over an hour -.0
25
- it 'writes a line to stdout'
40
+ def has_message?(io)
41
+ io.read_nonblock(1) # ~> IO::EAGAINWaitReadable: Resource temporarily unavailable - read would block
42
+ rescue Errno::EAGAIN
43
+ return false
44
+ end
45
+
46
+ it 'writes its events to the event stream' do
47
+ read, write = IO.pipe
48
+ producer = SeeingIsBelieving::EventStream::Producer.new(write)
49
+ expect(has_message? read).to eq false
50
+ producer.record_filename "whatever.rb"
51
+ expect(read.gets).to start_with 'filename'
52
+ end
26
53
 
27
- # This test is irrelevant on MRI b/c of the GIL,
28
- # but I ran it on Rbx to make sure it works
29
- it 'is wrapped in a mutex to prevent multiple values from writing at the same time' do
54
+ # This test is irrelevant on MRI b/c of the GIL, but I ran it on Rbx to make sure it works
55
+ it 'is threadsafe as multiple events can occur at once' do
30
56
  num_threads = 10
31
57
  num_results = 600
32
58
  line_nums_and_inspections = num_threads.times.flat_map { |line_num|
@@ -51,58 +77,58 @@ module SeeingIsBelieving::EventStream
51
77
  expect(producer_threads).to be_none(&:alive?)
52
78
  end
53
79
 
54
- it 'raises NoMoreInput and marks itself finished if input is closed before it finishes reading the number of requested inputs' do
55
- producer.finish!
80
+ it 'raises NoMoreInput if input is closed before it finishes reading the number of requested inputs' do
81
+ finish!
56
82
  expect { consumer.call 10 }.to raise_error SeeingIsBelieving::EventStream::Consumer::NoMoreInput
57
83
  end
58
84
 
59
- it 'raises NoMoreInput and marks itself finished once it receives the finish event' do
85
+ it 'raises NoMoreInput once it its input streams are all closed' do
60
86
  producer.finish!
61
- consumer.call 4
87
+ close_streams eventstream_producer, stdout_producer, stderr_producer
88
+ consumer.call 2
62
89
  expect { consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::NoMoreInput
63
- expect(consumer).to be_finished
64
90
  end
65
91
 
66
- it 'raises NoMoreInput and marks itself finished once the other end of the stream is closed' do
67
- writestream.close
92
+ it 'raises NoMoreInput if its end of the stream is closed and there is no more stdout/stderr' do
93
+ close_streams eventstream_consumer, stdout_producer, stderr_producer
94
+ expect { consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::WtfWhoClosedMyShit
68
95
  expect { consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::NoMoreInput
69
- expect(consumer).to be_finished
70
96
  end
71
97
 
72
- it 'raises WtfWhoClosedMyShit and marks itself finished if its end of the stream is closed' do
73
- readstream.close
98
+ it 'raises WtfWhoClosedMyShit if its end of the stream is closed' do
99
+ close_streams eventstream_consumer, stdout_producer, stderr_producer
74
100
  expect { consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::WtfWhoClosedMyShit
75
- expect(consumer).to be_finished
76
101
  end
77
102
  end
78
103
 
79
104
  describe 'each' do
80
- it 'loops through and yields all events except the finish event' do
105
+ it 'loops through and yields all events' do
81
106
  producer.record_result :inspect, 100, 2
82
- producer.finish!
107
+ finish!
83
108
 
84
109
  events = []
85
110
  consumer.each { |e| events << e }
86
- finish_event = events.find { |e| e.kind_of? Events::Finish }
87
111
  line_result = events.find { |e| e.kind_of? Events::LineResult }
88
112
  exitstatus = events.find { |e| e.kind_of? Events::Exitstatus }
89
- expect(finish_event).to be_nil
90
113
  expect(line_result.line_number).to eq 100
91
114
  expect(exitstatus.value).to eq 0
92
115
  end
93
116
 
94
117
  it 'stops looping if there is no more input' do
95
- writestream.close
96
- expect(consumer.each.map { |e| e }).to eq []
118
+ finish!
119
+ expect(consumer.each.map { |e| e }).to eq [
120
+ Events::NumLines.new(0),
121
+ Events::Exitstatus.new(0),
122
+ ]
97
123
  end
98
124
 
99
125
  it 'returns nil' do
100
- producer.finish!
126
+ finish!
101
127
  expect(consumer.each { 1 }).to eq nil
102
128
  end
103
129
 
104
130
  it 'returns an enumerator if not given a block' do
105
- producer.finish!
131
+ finish!
106
132
  expect(consumer.each.map &:class).to include Events::Exitstatus
107
133
  end
108
134
  end
@@ -257,6 +283,29 @@ module SeeingIsBelieving::EventStream
257
283
  end
258
284
  end
259
285
 
286
+ describe 'max_line_captures (value and recording)' do
287
+ it 'is infinity by default' do
288
+ expect(producer.max_line_captures).to eq Float::INFINITY
289
+ end
290
+
291
+ it 'emits the event and sets the max_line_captures' do
292
+ producer.record_max_line_captures 123
293
+ expect(producer.max_line_captures).to eq 123
294
+ expect(consumer.call).to eq Events::MaxLineCaptures.new(123)
295
+ end
296
+
297
+ it 'interprets numbers' do
298
+ producer.record_max_line_captures 12
299
+ expect(consumer.call).to eq Events::MaxLineCaptures.new(12)
300
+ end
301
+
302
+ it 'interprets infinity' do
303
+ producer.record_max_line_captures Float::INFINITY
304
+ expect(consumer.call).to eq Events::MaxLineCaptures.new(Float::INFINITY)
305
+ end
306
+ end
307
+
308
+
260
309
  describe 'exceptions' do
261
310
  def record_exception(linenum=nil, &raises_exception)
262
311
  raises_exception.call
@@ -326,45 +375,45 @@ module SeeingIsBelieving::EventStream
326
375
  context 'recorded line number | line num is provided | it knows the file | exception comes from within file' do
327
376
  let(:exception) { begin; raise "zomg"; rescue; $!; end }
328
377
  let(:linenum) { __LINE__ - 1 }
329
- it "provided one | true | true | true" do
378
+ example "provided one | true | true | true" do
330
379
  producer.filename = __FILE__
331
380
  producer.record_exception 12, exception
332
381
  assert_exception consumer.call, recorded_line_no: 12
333
382
  end
334
- it "provided one | true | true | false" do
383
+ example "provided one | true | true | false" do
335
384
  exception.backtrace.replace ['otherfile.rb']
336
385
  producer.record_exception 12, exception
337
386
  producer.filename = __FILE__
338
387
  assert_exception consumer.call, recorded_line_no: 12
339
388
  end
340
- it "provided one | true | false | true" do
389
+ example "provided one | true | false | true" do
341
390
  producer.filename = nil
342
391
  producer.record_exception 12, exception
343
392
  assert_exception consumer.call, recorded_line_no: 12
344
393
  end
345
- it "provided one | true | false | false" do
394
+ example "provided one | true | false | false" do
346
395
  exception.backtrace.replace ['otherfile.rb']
347
396
  producer.filename = nil
348
397
  producer.record_exception 12, exception
349
398
  assert_exception consumer.call, recorded_line_no: 12
350
399
  end
351
- it "from backtrace | false | true | true" do
400
+ example "from backtrace | false | true | true" do
352
401
  producer.filename = __FILE__
353
402
  producer.record_exception nil, exception
354
403
  assert_exception consumer.call, recorded_line_no: linenum
355
404
  end
356
- it "-1 | false | true | false" do
405
+ example "-1 | false | true | false" do
357
406
  exception.backtrace.replace ['otherfile.rb']
358
407
  producer.filename = __FILE__
359
408
  producer.record_exception nil, exception
360
409
  assert_exception consumer.call, recorded_line_no: -1
361
410
  end
362
- it "-1 | false | false | true" do
411
+ example "-1 | false | false | true" do
363
412
  producer.filename = nil
364
413
  producer.record_exception nil, exception
365
414
  assert_exception consumer.call, recorded_line_no: -1
366
415
  end
367
- it "-1 | false | false | false" do
416
+ example "-1 | false | false | false" do
368
417
  exception.backtrace.replace ['otherfile.rb']
369
418
  producer.filename = nil
370
419
  producer.record_exception nil, exception
@@ -373,40 +422,83 @@ module SeeingIsBelieving::EventStream
373
422
  end
374
423
  end
375
424
 
425
+ describe 'seeing is believing version' do
426
+ describe 'recording the version' do
427
+ it 'emits the version info' do
428
+ producer.record_sib_version '1.2.3'
429
+ expect(consumer.call).to eq Events::SiBVersion.new("1.2.3")
430
+ end
431
+ end
432
+
433
+ specify 'version return the version, if it has been set' do
434
+ expect(producer.version).to eq nil
435
+ producer.record_sib_version '4.5.6'
436
+ expect(producer.version).to eq '4.5.6'
437
+ end
438
+ end
439
+
440
+ describe 'record_ruby_version' do
441
+ it 'emits the ruby version info' do
442
+ producer.record_ruby_version 'o.m.g.'
443
+ expect(consumer.call).to eq Events::RubyVersion.new('o.m.g.')
444
+ end
445
+ end
446
+
447
+ describe 'record_filename' do
448
+ it 'sets the filename' do
449
+ producer.record_filename 'this-iz-mah-file.rb'
450
+ expect(producer.filename).to eq 'this-iz-mah-file.rb'
451
+ end
452
+ it 'emits the filename' do
453
+ producer.record_filename 'this-iz-mah-file.rb'
454
+ expect(consumer.call).to eq Events::Filename.new('this-iz-mah-file.rb')
455
+ end
456
+ end
457
+
376
458
  describe 'stdout' do
377
- it 'is an escaped string' do
378
- producer.record_stdout("this is the stdout¡")
379
- expect(consumer.call).to eq Events::Stdout.new("this is the stdout¡")
459
+ it 'is emitted along with the events from the event stream' do
460
+ stdout_producer.puts "this is the stdout¡"
461
+ expect(consumer.call).to eq Events::Stdout.new("this is the stdout¡\n")
462
+ end
463
+ specify 'each line is emitted as an event' do
464
+ stdout_producer.puts "first"
465
+ stdout_producer.puts "second\nthird"
466
+ expect(consumer.call).to eq Events::Stdout.new("first\n")
467
+ expect(consumer.call).to eq Events::Stdout.new("second\n")
468
+ expect(consumer.call).to eq Events::Stdout.new("third\n")
380
469
  end
381
470
  end
382
471
 
383
472
  describe 'stderr' do
384
- it 'is an escaped string' do
385
- producer.record_stderr("this is the stderr¡")
386
- expect(consumer.call).to eq Events::Stderr.new("this is the stderr¡")
473
+ it 'is emitted along with the events from the event stream' do
474
+ stderr_producer.puts "this is the stderr¡"
475
+ expect(consumer.call).to eq Events::Stderr.new("this is the stderr¡\n")
476
+ end
477
+ specify 'each line is emitted as an event' do
478
+ stderr_producer.puts "first"
479
+ stderr_producer.puts "second\nthird"
480
+ expect(consumer.call).to eq Events::Stderr.new("first\n")
481
+ expect(consumer.call).to eq Events::Stderr.new("second\n")
482
+ expect(consumer.call).to eq Events::Stderr.new("third\n")
387
483
  end
388
484
  end
389
485
 
486
+
390
487
  describe 'finish!' do
391
488
  def final_event(producer, consumer, event_class)
392
- producer.finish!
393
- consumer.call(4).find { |e| e.class == event_class }
489
+ finish!
490
+ consumer.call(2).find { |e| e.class == event_class }
394
491
  end
395
492
 
396
- describe 'max_line_captures' do
397
- it 'interprets numbers' do
398
- producer.max_line_captures = 12
399
- expect(final_event(producer, consumer, Events::MaxLineCaptures).value).to eq 12
400
- end
401
-
402
- it 'interprets infinity' do
403
- producer.max_line_captures = Float::INFINITY
404
- expect(final_event(producer, consumer, Events::MaxLineCaptures).value).to eq Float::INFINITY
405
- end
406
-
407
- it 'is infinity by default' do
408
- expect(final_event(producer, consumer, Events::MaxLineCaptures).value).to eq Float::INFINITY
409
- end
493
+ it 'stops the producer from producing' do
494
+ read, write = IO.pipe
495
+ producer = SeeingIsBelieving::EventStream::Producer.new write
496
+ producer.finish!
497
+ read.gets
498
+ read.gets
499
+ producer.record_filename("zomg")
500
+ write.close
501
+ expect(read.gets).to eq nil
410
502
  end
411
503
 
412
504
  describe 'num_lines' do
@@ -443,13 +535,12 @@ module SeeingIsBelieving::EventStream
443
535
  expect(final_event(producer, consumer, Events::Exitstatus).value).to eq 74
444
536
  end
445
537
  end
538
+ end
446
539
 
447
- describe 'finish' do
448
- it 'is the last thing that will be read' do
449
- expect(final_event(producer, consumer, Events::Finish)).to be_a_kind_of Events::Finish
450
- expect { p consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::NoMoreInput
451
- end
452
- end
540
+ specify 'if an incomprehensible event is received, it raises an UnknownEvent' do
541
+ eventstream_producer.puts "this is nonsense!"
542
+ eventstream_producer.close
543
+ expect{ consumer.call }.to raise_error SeeingIsBelieving::EventStream::Consumer::UnknownEvent, /nonsense/
453
544
  end
454
545
  end
455
546
  end