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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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