seeing_is_believing 3.0.0.beta.4 → 3.0.0.beta.5
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 +4 -4
- data/.travis.yml +0 -8
- data/Rakefile +1 -1
- data/Readme.md +65 -25
- data/bin/seeing_is_believing +1 -0
- data/docs/sib-streaming.gif +0 -0
- data/features/deprecated-flags.feature +62 -2
- data/features/errors.feature +12 -7
- data/features/examples.feature +143 -4
- data/features/flags.feature +89 -29
- data/features/regression.feature +58 -14
- data/features/support/env.rb +4 -0
- data/features/xmpfilter-style.feature +181 -36
- data/lib/seeing_is_believing.rb +44 -33
- data/lib/seeing_is_believing/binary.rb +31 -88
- data/lib/seeing_is_believing/binary/align_chunk.rb +30 -11
- data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +10 -16
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +5 -25
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +136 -0
- data/lib/seeing_is_believing/binary/comment_lines.rb +8 -10
- data/lib/seeing_is_believing/binary/commentable_lines.rb +20 -26
- data/lib/seeing_is_believing/binary/config.rb +392 -0
- data/lib/seeing_is_believing/binary/data_structures.rb +57 -0
- data/lib/seeing_is_believing/binary/engine.rb +104 -0
- data/lib/seeing_is_believing/binary/{comment_formatter.rb → format_comment.rb} +6 -6
- data/lib/seeing_is_believing/binary/remove_annotations.rb +29 -28
- data/lib/seeing_is_believing/binary/rewrite_comments.rb +42 -43
- data/lib/seeing_is_believing/code.rb +105 -49
- data/lib/seeing_is_believing/debugger.rb +6 -5
- data/lib/seeing_is_believing/error.rb +6 -17
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +78 -129
- data/lib/seeing_is_believing/event_stream/consumer.rb +114 -64
- data/lib/seeing_is_believing/event_stream/events.rb +169 -11
- data/lib/seeing_is_believing/event_stream/handlers/debug.rb +57 -0
- data/lib/seeing_is_believing/event_stream/handlers/record_exitstatus.rb +18 -0
- data/lib/seeing_is_believing/event_stream/handlers/stream_json_events.rb +45 -0
- data/lib/seeing_is_believing/event_stream/handlers/update_result.rb +39 -0
- data/lib/seeing_is_believing/event_stream/producer.rb +25 -24
- data/lib/seeing_is_believing/hash_struct.rb +206 -0
- data/lib/seeing_is_believing/result.rb +20 -3
- data/lib/seeing_is_believing/the_matrix.rb +20 -12
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +55 -115
- data/lib/seeing_is_believing/wrap_expressions_with_inspect.rb +14 -0
- data/seeing_is_believing.gemspec +1 -1
- data/spec/binary/alignment_specs.rb +27 -0
- data/spec/binary/comment_lines_spec.rb +3 -2
- data/spec/binary/config_spec.rb +657 -0
- data/spec/binary/engine_spec.rb +97 -0
- data/spec/binary/{comment_formatter_spec.rb → format_comment_spec.rb} +2 -2
- data/spec/binary/marker_spec.rb +71 -0
- data/spec/binary/options_spec.rb +0 -0
- data/spec/binary/remove_annotations_spec.rb +31 -18
- data/spec/binary/rewrite_comments_spec.rb +26 -11
- data/spec/code_spec.rb +190 -6
- data/spec/debugger_spec.rb +4 -0
- data/spec/evaluate_by_moving_files_spec.rb +38 -20
- data/spec/event_stream_spec.rb +265 -116
- data/spec/hash_struct_spec.rb +514 -0
- data/spec/seeing_is_believing_spec.rb +108 -46
- data/spec/spec_helper.rb +9 -0
- data/spec/wrap_expressions_spec.rb +207 -172
- metadata +30 -18
- data/docs/for-presentations +0 -33
- data/lib/seeing_is_believing/binary/annotate_xmpfilter_style.rb +0 -128
- data/lib/seeing_is_believing/binary/interpret_flags.rb +0 -156
- data/lib/seeing_is_believing/binary/parse_args.rb +0 -263
- data/lib/seeing_is_believing/event_stream/update_result.rb +0 -24
- data/lib/seeing_is_believing/inspect_expressions.rb +0 -21
- data/lib/seeing_is_believing/parser_helpers.rb +0 -82
- data/spec/binary/interpret_flags_spec.rb +0 -332
- data/spec/binary/parse_args_spec.rb +0 -415
data/spec/debugger_spec.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
require 'seeing_is_believing/evaluate_by_moving_files'
|
5
|
+
require 'seeing_is_believing/event_stream/handlers/update_result'
|
5
6
|
require 'fileutils'
|
6
7
|
|
7
8
|
RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
@@ -14,10 +15,17 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
14
15
|
'seeing_is_believing/the_matrix'
|
15
16
|
end
|
16
17
|
|
18
|
+
def null_options(overrides={})
|
19
|
+
{ event_handler: lambda { |*| } }
|
20
|
+
end
|
21
|
+
|
17
22
|
def invoke(program, options={})
|
23
|
+
result = SeeingIsBelieving::Result.new
|
24
|
+
options[:event_handler] ||= SeeingIsBelieving::EventStream::Handlers::UpdateResult.new(result)
|
18
25
|
evaluator = described_class.new(program, filename, options)
|
19
|
-
FileUtils.rm_f evaluator.
|
26
|
+
FileUtils.rm_f evaluator.backup_filename
|
20
27
|
evaluator.call
|
28
|
+
result
|
21
29
|
end
|
22
30
|
|
23
31
|
it 'evaluates the code when the file DNE' do
|
@@ -31,8 +39,8 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
31
39
|
end
|
32
40
|
|
33
41
|
it 'raises an error when the temp file already exists' do
|
34
|
-
evaluator = described_class.new('', filename)
|
35
|
-
FileUtils.touch evaluator.
|
42
|
+
evaluator = described_class.new('', filename, null_options)
|
43
|
+
FileUtils.touch evaluator.backup_filename
|
36
44
|
expect { evaluator.call }.to raise_error SeeingIsBelieving::TempFileAlreadyExists
|
37
45
|
end
|
38
46
|
|
@@ -47,29 +55,29 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
47
55
|
end
|
48
56
|
|
49
57
|
it 'uses HardCoreEnsure to move the file back' do
|
50
|
-
evaluator = described_class.new 'PROGRAM', filename
|
58
|
+
evaluator = described_class.new 'PROGRAM', filename, null_options
|
51
59
|
File.open(filename, 'w') { |f| f.write 'ORIGINAL' }
|
52
|
-
FileUtils.rm_rf evaluator.
|
60
|
+
FileUtils.rm_rf evaluator.backup_filename
|
53
61
|
expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
|
54
62
|
# initial state
|
55
|
-
expect(File.exist? evaluator.
|
63
|
+
expect(File.exist? evaluator.backup_filename).to eq false
|
56
64
|
expect(File.read filename).to eq 'ORIGINAL'
|
57
65
|
|
58
66
|
# after code
|
59
67
|
options[:code].call rescue nil
|
60
|
-
expect(File.read evaluator.
|
68
|
+
expect(File.read evaluator.backup_filename).to eq 'ORIGINAL'
|
61
69
|
expect(File.read filename).to eq 'PROGRAM'
|
62
70
|
|
63
71
|
# after ensure
|
64
72
|
options[:ensure].call
|
65
73
|
expect(File.read filename).to eq 'ORIGINAL'
|
66
|
-
expect(File.exist? evaluator.
|
74
|
+
expect(File.exist? evaluator.backup_filename).to eq false
|
67
75
|
end
|
68
76
|
evaluator.call
|
69
77
|
end
|
70
78
|
|
71
79
|
it 'uses HardCoreEnsure to delete the file if it wrote it where one did not previously exist' do
|
72
|
-
evaluator = described_class.new 'PROGRAM', filename
|
80
|
+
evaluator = described_class.new 'PROGRAM', filename, null_options
|
73
81
|
FileUtils.rm_rf filename
|
74
82
|
expect(SeeingIsBelieving::HardCoreEnsure).to receive(:call) do |options|
|
75
83
|
# initial state
|
@@ -91,13 +99,13 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
91
99
|
other_filename2 = File.join filedir, 'other2.rb'
|
92
100
|
File.open(other_filename1, 'w') { |f| f.puts "puts 123" }
|
93
101
|
File.open(other_filename2, 'w') { |f| f.puts "puts 456" }
|
94
|
-
result = invoke '',
|
102
|
+
result = invoke '', require_files: [matrix_file, other_filename1, other_filename2]
|
95
103
|
expect(result.stdout).to eq "123\n456\n"
|
96
104
|
end
|
97
105
|
|
98
106
|
it 'can set the load path' do
|
99
107
|
File.open(File.join(filedir, 'other1.rb'), 'w') { |f| f.puts "puts 123" }
|
100
|
-
result = invoke '',
|
108
|
+
result = invoke '', require_files: [matrix_file, 'other1'], load_path_dirs: [filedir]
|
101
109
|
expect(result.stdout).to eq "123\n"
|
102
110
|
end
|
103
111
|
|
@@ -111,16 +119,26 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
111
119
|
end
|
112
120
|
end
|
113
121
|
|
114
|
-
it 'if it fails, it tells the debugger some information and raises an error' do
|
115
|
-
error_stream = StringIO.new
|
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")
|
118
|
-
FileUtils.rm_f evaluator.temp_filename
|
119
|
-
expect { evaluator.call }.to raise_error SeeingIsBelieving::BugInSib
|
120
|
-
expect(error_stream.string).to include "Program could not be evaluated"
|
121
|
-
end
|
122
|
-
|
123
122
|
it 'does not blow up on exceptions raised in at_exit blocks' do
|
124
123
|
expect { invoke 'at_exit { raise "zomg" }' }.to_not raise_error
|
125
124
|
end
|
125
|
+
|
126
|
+
it 'can provide stdin as a string or stream' do
|
127
|
+
expect(invoke('p gets', provided_input: 'a').stdout).to eq %("a"\n)
|
128
|
+
require 'stringio'
|
129
|
+
result = invoke 'p gets', provided_input: StringIO.new('b')
|
130
|
+
expect(result.stdout).to eq %("b"\n)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'can set a timeout' do
|
134
|
+
expect(Timeout).to receive(:timeout).with(123).and_raise(Timeout::Error)
|
135
|
+
expect(Process).to receive(:kill)
|
136
|
+
expect { expect(invoke('p gets', timeout_seconds: 123).stdout).to eq %("a"\n) }
|
137
|
+
.to raise_error Timeout::Error
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'raises an ArgumentError if given arguments it doesn\'t know' do
|
141
|
+
expect { invoke '1', watisthis: :idontknow }
|
142
|
+
.to raise_error ArgumentError, /watisthis/
|
143
|
+
end
|
126
144
|
end
|
data/spec/event_stream_spec.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'seeing_is_believing/event_stream/producer'
|
4
4
|
require 'seeing_is_believing/event_stream/consumer'
|
5
|
+
require 'seeing_is_believing/event_stream/handlers/debug'
|
6
|
+
require 'seeing_is_believing/debugger'
|
5
7
|
|
6
8
|
module SeeingIsBelieving::EventStream
|
7
9
|
RSpec.describe SeeingIsBelieving::EventStream do
|
@@ -16,6 +18,7 @@ module SeeingIsBelieving::EventStream
|
|
16
18
|
|
17
19
|
def finish!
|
18
20
|
producer.finish!
|
21
|
+
consumer.process_exitstatus(0)
|
19
22
|
close_streams eventstream_producer, stdout_producer, stderr_producer
|
20
23
|
end
|
21
24
|
|
@@ -77,49 +80,88 @@ module SeeingIsBelieving::EventStream
|
|
77
80
|
expect(producer_threads).to be_none(&:alive?)
|
78
81
|
end
|
79
82
|
|
80
|
-
it '
|
83
|
+
it 'transcodes any received messages to UTF8' do
|
84
|
+
utf8 = "こんにちは" # from https://github.com/svenfuchs/i18n/blob/ee7fef8e9b9ee2f7d16e6c36d669ee7fb24ec613/lib/i18n/tests/interpolation.rb#L72
|
85
|
+
eucjp = utf8.encode(Encoding::EUCJP)
|
86
|
+
producer.record_sib_version(eucjp)
|
87
|
+
version = consumer.call.value
|
88
|
+
expect(version).to eq utf8
|
89
|
+
expect(version).to_not eq eucjp # general sanity checks to make
|
90
|
+
expect(utf8.bytes).to_not eq eucjp.bytes # sure I don't accidentally pass
|
91
|
+
end
|
92
|
+
|
93
|
+
def ascii8bit(str)
|
94
|
+
str.force_encoding Encoding::ASCII_8BIT
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'force encodes the message to UTF8 when it can\'t validly transcode' do
|
98
|
+
producer.record_sib_version(ascii8bit("åß∂ƒ"))
|
99
|
+
version = consumer.call.value
|
100
|
+
expect(version).to eq "åß∂ƒ"
|
101
|
+
expect(version).to_not eq ascii8bit("åß∂ƒ")
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'scrubs any invalid bytes to "�" when the force encoding isn\'t valid' do
|
105
|
+
producer.record_sib_version(ascii8bit "a\xFF å") # unicode bytes can't begin with
|
106
|
+
expect(consumer.call.value).to eq "a� å" # space just so its easier to see
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'raises NoMoreEvents if input is closed before it finishes reading the number of requested inputs' do
|
81
110
|
finish!
|
82
|
-
expect { consumer.call 10 }.to raise_error SeeingIsBelieving::
|
111
|
+
expect { consumer.call 10 }.to raise_error SeeingIsBelieving::NoMoreEvents
|
83
112
|
end
|
84
113
|
|
85
|
-
it 'raises
|
86
|
-
producer.finish!
|
114
|
+
it 'raises NoMoreEvents once it its input streams are all closed and its seen the exit status' do
|
87
115
|
close_streams eventstream_producer, stdout_producer, stderr_producer
|
88
|
-
|
89
|
-
|
116
|
+
producer.finish!
|
117
|
+
consumer.process_exitstatus 0
|
118
|
+
consumer.each { }
|
119
|
+
expect { consumer.call }.to raise_error SeeingIsBelieving::NoMoreEvents
|
90
120
|
end
|
91
121
|
|
92
|
-
it '
|
93
|
-
close_streams eventstream_consumer,
|
94
|
-
|
95
|
-
|
122
|
+
it 'gracefully handles its side of the streams getting closed' do
|
123
|
+
close_streams eventstream_consumer, stdout_consumer, stderr_consumer
|
124
|
+
consumer.process_exitstatus 0
|
125
|
+
consumer.each { }
|
126
|
+
expect { consumer.call }.to raise_error SeeingIsBelieving::NoMoreEvents
|
96
127
|
end
|
97
128
|
|
98
|
-
|
99
|
-
|
100
|
-
expect
|
129
|
+
specify 'if an incomprehensible event is received, it raises an UnknownEvent' do
|
130
|
+
eventstream_producer.puts "this is nonsense!"
|
131
|
+
expect{ consumer.call }.to raise_error SeeingIsBelieving::UnknownEvent, /nonsense/
|
101
132
|
end
|
102
133
|
end
|
103
134
|
|
104
135
|
describe 'each' do
|
105
136
|
it 'loops through and yields all events' do
|
137
|
+
# declare 2 events
|
106
138
|
producer.record_result :inspect, 100, 2
|
139
|
+
producer.record_sib_version('some ver')
|
140
|
+
|
141
|
+
# close streams so that it won't block waiting for more events
|
107
142
|
finish!
|
108
143
|
|
144
|
+
# record events
|
109
145
|
events = []
|
110
146
|
consumer.each { |e| events << e }
|
111
|
-
|
112
|
-
|
147
|
+
|
148
|
+
# it yielded the line result
|
149
|
+
line_result = events.find { |e| e.kind_of? Events::LineResult }
|
113
150
|
expect(line_result.line_number).to eq 100
|
114
|
-
|
151
|
+
|
152
|
+
# it yielded the version
|
153
|
+
version = events.find { |e| e.kind_of? Events::SiBVersion }
|
154
|
+
expect(version.value).to eq 'some ver'
|
115
155
|
end
|
116
156
|
|
117
157
|
it 'stops looping if there is no more input' do
|
158
|
+
producer.record_result :inspect, 100, 2
|
159
|
+
producer.record_sib_version('some ver')
|
118
160
|
finish!
|
119
|
-
expect(consumer.each.map { |e| e })
|
120
|
-
Events::
|
121
|
-
|
122
|
-
|
161
|
+
expect(consumer.each.map { |e| e.class }.sort_by(&:to_s))
|
162
|
+
.to eq [ Events::EventStreamClosed, Events::Exitstatus, Events::Finished,
|
163
|
+
Events::LineResult, Events::SiBVersion, Events::StderrClosed, Events::StdoutClosed,
|
164
|
+
]
|
123
165
|
end
|
124
166
|
|
125
167
|
it 'returns nil' do
|
@@ -128,8 +170,10 @@ module SeeingIsBelieving::EventStream
|
|
128
170
|
end
|
129
171
|
|
130
172
|
it 'returns an enumerator if not given a block' do
|
173
|
+
producer.record_sib_version('some ver')
|
131
174
|
finish!
|
132
|
-
|
175
|
+
classes = consumer.each.map &:class
|
176
|
+
expect(classes).to include Events::SiBVersion
|
133
177
|
end
|
134
178
|
end
|
135
179
|
|
@@ -147,15 +191,15 @@ module SeeingIsBelieving::EventStream
|
|
147
191
|
producer.record_result :type1, 123, "Ω≈ç√∫˜µ≤≥"
|
148
192
|
|
149
193
|
expect(consumer.call 9).to eq [
|
150
|
-
Events::LineResult.new(:type1, 123, [*'a'..'z', *'A'..'Z', *'0'..'9'].join("").inspect),
|
151
|
-
Events::LineResult.new(:type1, 123, '"'.inspect),
|
152
|
-
Events::LineResult.new(:type1, 123, '""'.inspect),
|
153
|
-
Events::LineResult.new(:type1, 123, "\n".inspect),
|
154
|
-
Events::LineResult.new(:type1, 123, "\r".inspect),
|
155
|
-
Events::LineResult.new(:type1, 123, "\n\r\n".inspect),
|
156
|
-
Events::LineResult.new(:type1, 123, "\#{}".inspect),
|
157
|
-
Events::LineResult.new(:type1, 123, [*0..127].map(&:chr).join("").inspect),
|
158
|
-
Events::LineResult.new(:type1, 123, "Ω≈ç√∫˜µ≤≥".inspect),
|
194
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: [*'a'..'z', *'A'..'Z', *'0'..'9'].join("").inspect),
|
195
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: '"'.inspect),
|
196
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: '""'.inspect),
|
197
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: "\n".inspect),
|
198
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: "\r".inspect),
|
199
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: "\n\r\n".inspect),
|
200
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: "\#{}".inspect),
|
201
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: [*0..127].map(&:chr).join("").inspect),
|
202
|
+
Events::LineResult.new(type: :type1, line_number: 123, inspected: "Ω≈ç√∫˜µ≤≥".inspect),
|
159
203
|
]
|
160
204
|
end
|
161
205
|
|
@@ -163,16 +207,16 @@ module SeeingIsBelieving::EventStream
|
|
163
207
|
producer.max_line_captures = 2
|
164
208
|
|
165
209
|
producer.record_result :type1, 123, 1
|
166
|
-
expect(consumer.call 1).to eq Events::LineResult.new(:type1, 123, '1')
|
210
|
+
expect(consumer.call 1).to eq Events::LineResult.new(type: :type1, line_number: 123, inspected: '1')
|
167
211
|
|
168
212
|
producer.record_result :type1, 123, 2
|
169
|
-
expect(consumer.call 1).to eq Events::LineResult.new(:type1, 123, '2')
|
213
|
+
expect(consumer.call 1).to eq Events::LineResult.new(type: :type1, line_number: 123, inspected: '2')
|
170
214
|
|
171
215
|
producer.record_result :type1, 123, 3
|
172
216
|
producer.record_result :type1, 123, 4
|
173
217
|
producer.record_result :type2, 123, 1
|
174
|
-
expect(consumer.call 2).to eq [Events::
|
175
|
-
Events::LineResult.new(:type2, 123, '1')]
|
218
|
+
expect(consumer.call 2).to eq [Events::ResultsTruncated.new(type: :type1, line_number: 123),
|
219
|
+
Events::LineResult.new(type: :type2, line_number: 123, inspected: '1')]
|
176
220
|
end
|
177
221
|
|
178
222
|
it 'scopes the max to a given type/line' do
|
@@ -185,12 +229,12 @@ module SeeingIsBelieving::EventStream
|
|
185
229
|
producer.record_result :type2, 1, 5
|
186
230
|
producer.record_result :type2, 1, 6
|
187
231
|
expect(consumer.call 6).to eq [
|
188
|
-
Events::LineResult.new(:type1, 1, '1'),
|
189
|
-
Events::
|
190
|
-
Events::LineResult.new(:type1, 2, '3'),
|
191
|
-
Events::
|
192
|
-
Events::LineResult.new(:type2, 1, '5'),
|
193
|
-
Events::
|
232
|
+
Events::LineResult.new( type: :type1, line_number: 1, inspected: '1'),
|
233
|
+
Events::ResultsTruncated.new(type: :type1, line_number: 1),
|
234
|
+
Events::LineResult.new( type: :type1, line_number: 2, inspected: '3'),
|
235
|
+
Events::ResultsTruncated.new(type: :type1, line_number: 2),
|
236
|
+
Events::LineResult.new( type: :type2, line_number: 1, inspected: '5'),
|
237
|
+
Events::ResultsTruncated.new(type: :type2, line_number: 1),
|
194
238
|
]
|
195
239
|
end
|
196
240
|
|
@@ -202,10 +246,10 @@ module SeeingIsBelieving::EventStream
|
|
202
246
|
# Some examples, mostly for the purpose of running individually if things get confusing
|
203
247
|
example 'Example: Simple' do
|
204
248
|
producer.record_result :type, 1, "a"
|
205
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, '"a"')
|
249
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: '"a"')
|
206
250
|
|
207
251
|
producer.record_result :type, 1, 1
|
208
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, '1')
|
252
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: '1')
|
209
253
|
end
|
210
254
|
|
211
255
|
example 'Example: Complex' do
|
@@ -213,14 +257,14 @@ module SeeingIsBelieving::EventStream
|
|
213
257
|
str2 = str1.dup
|
214
258
|
producer.record_result :type, 1, str2
|
215
259
|
expect(str2).to eq str1 # just making sure it doesn't mutate since this one is so complex
|
216
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, str1.inspect)
|
260
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: str1.inspect)
|
217
261
|
end
|
218
262
|
|
219
263
|
context 'calls #inspect when no block is given' do
|
220
264
|
it "doesn't blow up when there is no #inspect available e.g. BasicObject" do
|
221
265
|
obj = BasicObject.new
|
222
266
|
producer.record_result :type, 1, obj
|
223
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, "#<no inspect available>")
|
267
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: "#<no inspect available>")
|
224
268
|
end
|
225
269
|
|
226
270
|
|
@@ -230,7 +274,7 @@ module SeeingIsBelieving::EventStream
|
|
230
274
|
nil
|
231
275
|
end
|
232
276
|
producer.record_result :type, 1, obj
|
233
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, "#<no inspect available>")
|
277
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: "#<no inspect available>")
|
234
278
|
end
|
235
279
|
|
236
280
|
it 'only calls inspect once' do
|
@@ -250,24 +294,24 @@ module SeeingIsBelieving::EventStream
|
|
250
294
|
def o.inspect() 'real-inspect' end
|
251
295
|
def o.other_inspect() 'other-inspect' end
|
252
296
|
producer.record_result(:type, 1, o) { |x| x.other_inspect }
|
253
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, 'other-inspect')
|
297
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: 'other-inspect')
|
254
298
|
end
|
255
299
|
|
256
300
|
it 'doesn\'t blow up if the block raises' do
|
257
301
|
o = Object.new
|
258
302
|
producer.record_result(:type, 1, o) { raise Exception, "zomg" }
|
259
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, '#<no inspect available>')
|
303
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: '#<no inspect available>')
|
260
304
|
end
|
261
305
|
|
262
306
|
it 'doesn\'t blow up if the block returns a non-string' do
|
263
307
|
o = Object.new
|
264
308
|
producer.record_result(:type, 1, o) { nil }
|
265
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, '#<no inspect available>')
|
309
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: '#<no inspect available>')
|
266
310
|
|
267
311
|
stringish = Object.new
|
268
312
|
def stringish.to_str() 'actual string' end
|
269
313
|
producer.record_result(:type, 1, o) { stringish }
|
270
|
-
expect(consumer.call).to eq Events::LineResult.new(:type, 1, 'actual string')
|
314
|
+
expect(consumer.call).to eq Events::LineResult.new(type: :type, line_number: 1, inspected: 'actual string')
|
271
315
|
end
|
272
316
|
|
273
317
|
it 'invokes the block only once' do
|
@@ -291,17 +335,17 @@ module SeeingIsBelieving::EventStream
|
|
291
335
|
it 'emits the event and sets the max_line_captures' do
|
292
336
|
producer.record_max_line_captures 123
|
293
337
|
expect(producer.max_line_captures).to eq 123
|
294
|
-
expect(consumer.call).to eq Events::MaxLineCaptures.new(123)
|
338
|
+
expect(consumer.call).to eq Events::MaxLineCaptures.new(value: 123)
|
295
339
|
end
|
296
340
|
|
297
341
|
it 'interprets numbers' do
|
298
342
|
producer.record_max_line_captures 12
|
299
|
-
expect(consumer.call).to eq Events::MaxLineCaptures.new(12)
|
343
|
+
expect(consumer.call).to eq Events::MaxLineCaptures.new(value: 12)
|
300
344
|
end
|
301
345
|
|
302
346
|
it 'interprets infinity' do
|
303
347
|
producer.record_max_line_captures Float::INFINITY
|
304
|
-
expect(consumer.call).to eq Events::MaxLineCaptures.new(Float::INFINITY)
|
348
|
+
expect(consumer.call).to eq Events::MaxLineCaptures.new(value: Float::INFINITY)
|
305
349
|
end
|
306
350
|
end
|
307
351
|
|
@@ -352,23 +396,17 @@ module SeeingIsBelieving::EventStream
|
|
352
396
|
end
|
353
397
|
|
354
398
|
context 'when the exception is a SystemExit' do
|
355
|
-
it '
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
expect(producer.exitstatus).to eq 0
|
362
|
-
record_exception { exit true }
|
363
|
-
expect(producer.exitstatus).to eq 0
|
364
|
-
record_exception { exit false }
|
365
|
-
expect(producer.exitstatus).to eq 1
|
366
|
-
end
|
399
|
+
it 'returns the status and does not record the exception' do
|
400
|
+
exception = nil
|
401
|
+
begin exit 22
|
402
|
+
rescue SystemExit
|
403
|
+
exception = $!
|
404
|
+
end
|
367
405
|
|
368
|
-
|
369
|
-
expect(
|
370
|
-
|
371
|
-
expect(
|
406
|
+
exitstatus = producer.record_exception(1, exception)
|
407
|
+
expect(exitstatus).to eq 22
|
408
|
+
finish!
|
409
|
+
expect(consumer.each.find { |e| e.kind_of? Events::Exception }).to eq nil
|
372
410
|
end
|
373
411
|
end
|
374
412
|
|
@@ -426,7 +464,7 @@ module SeeingIsBelieving::EventStream
|
|
426
464
|
describe 'recording the version' do
|
427
465
|
it 'emits the version info' do
|
428
466
|
producer.record_sib_version '1.2.3'
|
429
|
-
expect(consumer.call).to eq Events::SiBVersion.new("1.2.3")
|
467
|
+
expect(consumer.call).to eq Events::SiBVersion.new(value: "1.2.3")
|
430
468
|
end
|
431
469
|
end
|
432
470
|
|
@@ -440,7 +478,7 @@ module SeeingIsBelieving::EventStream
|
|
440
478
|
describe 'record_ruby_version' do
|
441
479
|
it 'emits the ruby version info' do
|
442
480
|
producer.record_ruby_version 'o.m.g.'
|
443
|
-
expect(consumer.call).to eq Events::RubyVersion.new('o.m.g.')
|
481
|
+
expect(consumer.call).to eq Events::RubyVersion.new(value: 'o.m.g.')
|
444
482
|
end
|
445
483
|
end
|
446
484
|
|
@@ -451,96 +489,207 @@ module SeeingIsBelieving::EventStream
|
|
451
489
|
end
|
452
490
|
it 'emits the filename' do
|
453
491
|
producer.record_filename 'this-iz-mah-file.rb'
|
454
|
-
expect(consumer.call).to eq Events::Filename.new('this-iz-mah-file.rb')
|
492
|
+
expect(consumer.call).to eq Events::Filename.new(value: 'this-iz-mah-file.rb')
|
455
493
|
end
|
456
494
|
end
|
457
495
|
|
458
496
|
describe 'stdout' do
|
459
497
|
it 'is emitted along with the events from the event stream' do
|
460
498
|
stdout_producer.puts "this is the stdout¡"
|
461
|
-
expect(consumer.call).to eq Events::Stdout.new("this is the stdout¡\n")
|
499
|
+
expect(consumer.call).to eq Events::Stdout.new(value: "this is the stdout¡\n")
|
462
500
|
end
|
463
501
|
specify 'each line is emitted as an event' do
|
464
502
|
stdout_producer.puts "first"
|
465
503
|
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")
|
504
|
+
expect(consumer.call).to eq Events::Stdout.new(value: "first\n")
|
505
|
+
expect(consumer.call).to eq Events::Stdout.new(value: "second\n")
|
506
|
+
expect(consumer.call).to eq Events::Stdout.new(value: "third\n")
|
469
507
|
end
|
470
508
|
end
|
471
509
|
|
472
510
|
describe 'stderr' do
|
473
511
|
it 'is emitted along with the events from the event stream' do
|
474
512
|
stderr_producer.puts "this is the stderr¡"
|
475
|
-
expect(consumer.call).to eq Events::Stderr.new("this is the stderr¡\n")
|
513
|
+
expect(consumer.call).to eq Events::Stderr.new(value: "this is the stderr¡\n")
|
476
514
|
end
|
477
515
|
specify 'each line is emitted as an event' do
|
478
516
|
stderr_producer.puts "first"
|
479
517
|
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")
|
518
|
+
expect(consumer.call).to eq Events::Stderr.new(value: "first\n")
|
519
|
+
expect(consumer.call).to eq Events::Stderr.new(value: "second\n")
|
520
|
+
expect(consumer.call).to eq Events::Stderr.new(value: "third\n")
|
483
521
|
end
|
484
522
|
end
|
485
523
|
|
524
|
+
describe 'record_exec' do
|
525
|
+
it 'records the event and the inspection of the args that were given to exec' do
|
526
|
+
producer.record_exec(["ls", "-l"])
|
527
|
+
expect(consumer.call).to eq Events::Exec.new(args: '["ls", "-l"]')
|
528
|
+
end
|
529
|
+
end
|
486
530
|
|
487
|
-
describe '
|
488
|
-
|
489
|
-
|
490
|
-
consumer.call
|
531
|
+
describe 'record_num_lines' do
|
532
|
+
it 'interprets numbers' do
|
533
|
+
producer.record_num_lines 21
|
534
|
+
expect(consumer.call).to eq Events::NumLines.new(value: 21)
|
491
535
|
end
|
536
|
+
end
|
492
537
|
|
538
|
+
describe 'finish!' do
|
493
539
|
it 'stops the producer from producing' do
|
494
540
|
read, write = IO.pipe
|
495
541
|
producer = SeeingIsBelieving::EventStream::Producer.new write
|
496
542
|
producer.finish!
|
497
|
-
read.gets
|
498
|
-
read.gets
|
499
543
|
producer.record_filename("zomg")
|
500
544
|
write.close
|
501
545
|
expect(read.gets).to eq nil
|
502
546
|
end
|
547
|
+
end
|
503
548
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
549
|
+
describe 'final events' do
|
550
|
+
it 'emits a StdoutClosed event when consumer side of stdout closes' do
|
551
|
+
stdout_consumer.close
|
552
|
+
expect(consumer.call).to eq Events::StdoutClosed.new(side: :consumer)
|
553
|
+
end
|
554
|
+
it 'emits a StdoutClosed event when producer side of stdout closes' do
|
555
|
+
stdout_producer.close
|
556
|
+
expect(consumer.call).to eq Events::StdoutClosed.new(side: :producer)
|
557
|
+
end
|
509
558
|
|
510
|
-
|
511
|
-
|
512
|
-
|
559
|
+
it 'emits a StderrClosed event when consumer side of stderr closes' do
|
560
|
+
stderr_consumer.close
|
561
|
+
expect(consumer.call).to eq Events::StderrClosed.new(side: :consumer)
|
562
|
+
end
|
563
|
+
it 'emits a StderrClosed event when producer side of stderr closes' do
|
564
|
+
stderr_producer.close
|
565
|
+
expect(consumer.call).to eq Events::StderrClosed.new(side: :producer)
|
566
|
+
end
|
513
567
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
568
|
+
it 'emits a EventStreamClosed event when consumer side of event_stream closes' do
|
569
|
+
eventstream_consumer.close
|
570
|
+
expect(consumer.call).to eq Events::EventStreamClosed.new(side: :consumer)
|
571
|
+
end
|
572
|
+
it 'emits a EventStreamClosed event when producer side of event_stream closes' do
|
573
|
+
eventstream_producer.close
|
574
|
+
expect(consumer.call).to eq Events::EventStreamClosed.new(side: :producer)
|
575
|
+
end
|
519
576
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
producer.record_exception 100, e
|
524
|
-
expect(final_event(producer, consumer, Events::NumLines).value).to eq 100
|
525
|
-
end
|
577
|
+
it 'emits a Exitstatus event on process_exitstatus' do
|
578
|
+
consumer.process_exitstatus 92
|
579
|
+
expect(consumer.call).to eq Events::Exitstatus.new(value: 92)
|
526
580
|
end
|
527
581
|
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
582
|
+
it 'emits a Finished event when all streams are closed and it has the exit status' do
|
583
|
+
finish!
|
584
|
+
event_classes = consumer.each.map(&:class)
|
585
|
+
expect(event_classes).to include Events::Finished
|
586
|
+
end
|
587
|
+
end
|
532
588
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
589
|
+
describe Events do
|
590
|
+
specify 'Event raises an error if .event_name was not overridden' do
|
591
|
+
expect { Event.event_name }.to raise_error NotImplementedError
|
592
|
+
end
|
593
|
+
specify 'all events have a reasonable event name' do
|
594
|
+
pairs = [
|
595
|
+
[Events::Stdout , :stdout],
|
596
|
+
[Events::Stderr , :stderr],
|
597
|
+
[Events::MaxLineCaptures , :max_line_captures],
|
598
|
+
[Events::Filename , :filename],
|
599
|
+
[Events::NumLines , :num_lines],
|
600
|
+
[Events::SiBVersion , :sib_version],
|
601
|
+
[Events::RubyVersion , :ruby_version],
|
602
|
+
[Events::Exitstatus , :exitstatus],
|
603
|
+
[Events::Exec , :exec],
|
604
|
+
[Events::ResultsTruncated , :results_truncated],
|
605
|
+
[Events::LineResult , :line_result],
|
606
|
+
[Events::Exception , :exception],
|
607
|
+
[Events::StdoutClosed , :stdout_closed],
|
608
|
+
[Events::StderrClosed , :stderr_closed],
|
609
|
+
[Events::EventStreamClosed, :event_stream_closed],
|
610
|
+
[Events::Finished , :finished],
|
611
|
+
]
|
612
|
+
pairs.each { |klass, name| expect(klass.event_name).to eq name }
|
613
|
+
|
614
|
+
events_we_tested = pairs.map(&:first).flatten
|
615
|
+
event_classes = Events.constants.map { |name| Events.const_get name }
|
616
|
+
expect(event_classes - events_we_tested).to eq []
|
617
|
+
end
|
618
|
+
specify 'their event_name and attributes are included in their as_json' do
|
619
|
+
expect(Events::Stdout.new(value: "abc").as_json).to eq [:stdout, {value: "abc"}]
|
620
|
+
end
|
621
|
+
specify 'MaxLineCaptures#as_json includes is_infinity, and sets value to -1 in this case' do
|
622
|
+
expect(Events::MaxLineCaptures.new(value: Float::INFINITY).as_json).to eq [:max_line_captures, {value: -1, is_infinity: true}]
|
623
|
+
expect(Events::MaxLineCaptures.new(value: 123).as_json).to eq [:max_line_captures, {value: 123, is_infinity: false}]
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
require 'seeing_is_believing/event_stream/handlers/stream_json_events'
|
628
|
+
describe Handlers::StreamJsonEvents do
|
629
|
+
it 'writes each event\'s json representation to the stream' do
|
630
|
+
stream = ""
|
631
|
+
handler = described_class.new stream
|
632
|
+
|
633
|
+
handler.call Events::Stdout.new(value: "abc")
|
634
|
+
expect(stream).to eq %'["stdout",{"value":"abc"}]\n'
|
635
|
+
|
636
|
+
handler.call Events::Finished.new
|
637
|
+
expect(stream).to eq %'["stdout",{"value":"abc"}]\n'+
|
638
|
+
%'["finished",{}]\n'
|
639
|
+
end
|
640
|
+
|
641
|
+
it 'calls flush after each event, when the stream responds to it' do
|
642
|
+
stream = object_spy $stdout
|
643
|
+
flushcount = 0
|
644
|
+
allow(stream).to receive(:flush) { flushcount += 1 }
|
645
|
+
|
646
|
+
handler = described_class.new stream
|
647
|
+
expect(flushcount).to eq 0
|
648
|
+
|
649
|
+
handler.call Events::Stdout.new(value: "abc")
|
650
|
+
expect(flushcount).to eq 1
|
651
|
+
|
652
|
+
handler.call Events::Finished.new
|
653
|
+
expect(flushcount).to eq 2
|
537
654
|
end
|
538
655
|
end
|
539
656
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
657
|
+
describe Handlers::Debug do
|
658
|
+
let(:stream) { "" }
|
659
|
+
let(:events_seen) { [] }
|
660
|
+
let(:debugger) { SeeingIsBelieving::Debugger.new stream: stream }
|
661
|
+
let(:parent_observer) { lambda { |event| events_seen << event } }
|
662
|
+
let(:debug_handler) { described_class.new(debugger, parent_observer) }
|
663
|
+
|
664
|
+
it 'passes events through to the parent observer' do
|
665
|
+
event = Events::Stdout.new(value: "zomg")
|
666
|
+
debug_handler.call(event)
|
667
|
+
expect(events_seen).to eq [event]
|
668
|
+
end
|
669
|
+
|
670
|
+
it 'generally prints things, prettily, wide and short' do
|
671
|
+
[ Events::Stdout.new(value: "short"),
|
672
|
+
Events::Stdout.new(value: "long"*1000),
|
673
|
+
Events::Exec.new(args: ["a", "b", "c"]),
|
674
|
+
Events::StdoutClosed.new(side: :consumer),
|
675
|
+
Events::Exception.new(line_number: 100,
|
676
|
+
class_name: "SomethingException",
|
677
|
+
message: "The things, they blew up!",
|
678
|
+
backtrace: ["a"*10,"b"*2000]),
|
679
|
+
Events::Finished.new,
|
680
|
+
].each { |event| debug_handler.call event }
|
681
|
+
|
682
|
+
expect(stream).to match /^Stdout\b/ # the events al made it
|
683
|
+
expect(stream).to match /^Exec\b/
|
684
|
+
expect(stream).to match /^StdoutClosed\b/
|
685
|
+
expect(stream).to match /^Exception\b/
|
686
|
+
expect(stream).to match /^Finished\b/
|
687
|
+
expect(stream).to match /^\| - a+/ # a backtrace in there
|
688
|
+
expect(stream).to match /\.{3}$/ # truncation indication
|
689
|
+
stream.each_line do |line|
|
690
|
+
expect(line.length).to be <= 151 # long lines got truncated (151 b/c newline is counted)
|
691
|
+
end
|
692
|
+
end
|
544
693
|
end
|
545
694
|
end
|
546
695
|
end
|