seeing_is_believing 3.1.1 → 3.2.0
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 +1 -0
- data/Rakefile +43 -16
- data/Readme.md +27 -242
- data/appveyor.yml +29 -0
- data/bin/seeing_is_believing +2 -1
- data/features/deprecated-flags.feature +19 -0
- data/features/errors.feature +57 -0
- data/features/examples.feature +4 -2
- data/features/flags.feature +35 -2
- data/features/regression.feature +107 -10
- data/features/support/env.rb +61 -2
- data/features/xmpfilter-style.feature +3 -2
- data/lib/seeing_is_believing/binary/annotate_end_of_file.rb +11 -9
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +9 -8
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +9 -8
- data/lib/seeing_is_believing/binary/config.rb +19 -3
- data/lib/seeing_is_believing/binary/engine.rb +5 -10
- data/lib/seeing_is_believing/evaluate_by_moving_files.rb +60 -45
- data/lib/seeing_is_believing/event_stream/consumer.rb +6 -1
- data/lib/seeing_is_believing/event_stream/handlers/debug.rb +5 -1
- data/lib/seeing_is_believing/event_stream/producer.rb +1 -1
- data/lib/seeing_is_believing/hard_core_ensure.rb +6 -0
- data/lib/seeing_is_believing/result.rb +26 -14
- data/lib/seeing_is_believing/safe.rb +6 -1
- data/lib/seeing_is_believing/the_matrix.rb +16 -4
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +1 -1
- data/lib/seeing_is_believing.rb +7 -10
- data/seeing_is_believing.gemspec +9 -8
- data/spec/binary/config_spec.rb +65 -4
- data/spec/binary/engine_spec.rb +1 -1
- data/spec/evaluate_by_moving_files_spec.rb +31 -5
- data/spec/event_stream_spec.rb +14 -6
- data/spec/hard_core_ensure_spec.rb +70 -44
- data/spec/seeing_is_believing_spec.rb +136 -42
- data/spec/spec_helper.rb +8 -0
- data/spec/wrap_expressions_spec.rb +15 -0
- metadata +21 -6
@@ -1,6 +1,10 @@
|
|
1
1
|
class SeeingIsBelieving
|
2
2
|
module EventStream
|
3
3
|
module Handlers
|
4
|
+
# Even though the debugger can be disabled, which would push the decision of
|
5
|
+
# whether to report or not into the debugger where it belongs, you should still
|
6
|
+
# avoid using this class if you don't need it since it is expensive and there
|
7
|
+
# could be tens of millions of events, eg https://github.com/JoshCheek/seeing_is_believing/issues/12
|
4
8
|
class Debug
|
5
9
|
def initialize(debugger, handler)
|
6
10
|
@debugger = debugger
|
@@ -22,7 +26,7 @@ class SeeingIsBelieving
|
|
22
26
|
attr_reader :debugger, :handler
|
23
27
|
|
24
28
|
def finish
|
25
|
-
@debugger.context("EVENTS
|
29
|
+
@debugger.context("EVENTS") { @seen }
|
26
30
|
end
|
27
31
|
|
28
32
|
def observe(event)
|
@@ -25,6 +25,7 @@ class SeeingIsBelieving
|
|
25
25
|
invoke_ensure
|
26
26
|
Process.kill 'INT', $$
|
27
27
|
end
|
28
|
+
trap 'INT', old_handler if ignore_interrupt? old_handler
|
28
29
|
end
|
29
30
|
|
30
31
|
def invoke_code
|
@@ -48,5 +49,10 @@ class SeeingIsBelieving
|
|
48
49
|
raise ArgumentError, "Unknown keys: #{unknown_keys.map(&:inspect).join(', ')}"
|
49
50
|
end
|
50
51
|
end
|
52
|
+
|
53
|
+
def ignore_interrupt?(interrupt_handler)
|
54
|
+
# any handler that ignores gets normalized to IGNORE
|
55
|
+
interrupt_handler == 'IGNORE'
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
@@ -3,14 +3,17 @@ 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, :max_line_captures, :
|
6
|
+
attr_accessor :stdout, :stderr, :exitstatus, :max_line_captures, :exceptions, :num_lines, :sib_version, :ruby_version, :filename, :timeout_seconds
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
self.stderr = ''
|
8
|
+
def has_exception?
|
9
|
+
exceptions.any?
|
11
10
|
end
|
12
11
|
|
13
|
-
|
12
|
+
def initialize
|
13
|
+
self.stdout = ''
|
14
|
+
self.stderr = ''
|
15
|
+
self.exceptions = []
|
16
|
+
end
|
14
17
|
|
15
18
|
def has_stdout?
|
16
19
|
stdout && !stdout.empty?
|
@@ -30,7 +33,11 @@ class SeeingIsBelieving
|
|
30
33
|
end
|
31
34
|
|
32
35
|
def record_exception(line_number, exception_class, exception_message, exception_backtrace)
|
33
|
-
self.
|
36
|
+
self.exceptions << RecordedException.new(line_number, exception_class, exception_message, exception_backtrace)
|
37
|
+
end
|
38
|
+
|
39
|
+
def exception
|
40
|
+
exceptions.first
|
34
41
|
end
|
35
42
|
|
36
43
|
def [](line_number, type=:inspect)
|
@@ -47,17 +54,13 @@ class SeeingIsBelieving
|
|
47
54
|
end
|
48
55
|
|
49
56
|
def as_json
|
50
|
-
|
51
|
-
|
52
|
-
class_name: exception.class_name,
|
53
|
-
message: exception.message,
|
54
|
-
backtrace: exception.backtrace,
|
55
|
-
}
|
56
|
-
|
57
|
+
# We have both an exception and a list of exceptions because multiple exceptions
|
58
|
+
# weren't added until #85, and I don't want to break backwards compatibility right now.
|
57
59
|
{ stdout: stdout,
|
58
60
|
stderr: stderr,
|
59
61
|
exitstatus: exitstatus,
|
60
|
-
exception:
|
62
|
+
exception: exception_json(exception),
|
63
|
+
exceptions: exceptions.map { |e| exception_json e },
|
61
64
|
lines: each.with_object(Hash.new)
|
62
65
|
.with_index(1) { |(result, hash), line_number| hash[line_number] = result },
|
63
66
|
}
|
@@ -73,5 +76,14 @@ class SeeingIsBelieving
|
|
73
76
|
def results
|
74
77
|
@results ||= Hash.new
|
75
78
|
end
|
79
|
+
|
80
|
+
def exception_json(exception)
|
81
|
+
return nil unless exception
|
82
|
+
{ line_number_in_this_file: exception.line_number,
|
83
|
+
class_name: exception.class_name,
|
84
|
+
message: exception.message,
|
85
|
+
backtrace: exception.backtrace,
|
86
|
+
}
|
87
|
+
end
|
76
88
|
end
|
77
89
|
end
|
@@ -21,7 +21,6 @@ class SeeingIsBelieving
|
|
21
21
|
refine Symbol do
|
22
22
|
alias == ==
|
23
23
|
alias to_s to_s
|
24
|
-
alias inspect inspect
|
25
24
|
end
|
26
25
|
|
27
26
|
refine Symbol.singleton_class do
|
@@ -35,6 +34,12 @@ class SeeingIsBelieving
|
|
35
34
|
alias to_str to_str
|
36
35
|
end
|
37
36
|
|
37
|
+
# in 2.4 we should use Integer instead, but it's not obvious to me how
|
38
|
+
# to detect this. eg defined?(Fixnum) returns "constant". Accessing it
|
39
|
+
# leads to a warning, but SiB turns warnings off so you don't see it.
|
40
|
+
# So.... for now, it incidentally doesn't do anything annoying, but would
|
41
|
+
# be good to figure out something better (eg if we ever wanted to allow the
|
42
|
+
# user to decide whether warnings should display or not)
|
38
43
|
refine Fixnum do
|
39
44
|
alias to_s to_s
|
40
45
|
alias next next
|
@@ -1,11 +1,21 @@
|
|
1
1
|
require_relative 'safe'
|
2
2
|
require_relative 'version'
|
3
3
|
require_relative 'event_stream/producer'
|
4
|
+
require 'socket'
|
5
|
+
require 'timeout'
|
4
6
|
|
5
7
|
using SeeingIsBelieving::Safe
|
6
8
|
|
7
9
|
sib_vars = Marshal.load ENV["SIB_VARIABLES.MARSHAL.B64"].unpack('m0').first
|
8
|
-
event_stream =
|
10
|
+
event_stream = Timeout.timeout(1) do
|
11
|
+
begin
|
12
|
+
Socket.tcp("localhost", sib_vars.fetch(:event_stream_port))
|
13
|
+
rescue Errno::ECONNREFUSED
|
14
|
+
sleep 0.1
|
15
|
+
retry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
9
19
|
$SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
|
10
20
|
$SiB.record_ruby_version RUBY_VERSION
|
11
21
|
$SiB.record_sib_version SeeingIsBelieving::VERSION
|
@@ -14,13 +24,16 @@ $SiB.record_num_lines sib_vars.fetch(:num_lines)
|
|
14
24
|
$SiB.record_max_line_captures sib_vars.fetch(:max_line_captures)
|
15
25
|
|
16
26
|
STDOUT.sync = true
|
27
|
+
STDOUT.binmode
|
28
|
+
STDERR.binmode
|
29
|
+
STDIN.set_encoding "utf-8"
|
17
30
|
stdout, stderr = STDOUT, STDERR
|
18
31
|
|
19
32
|
finish = lambda do
|
20
33
|
$SiB.finish!
|
21
34
|
event_stream.close
|
22
|
-
stdout.flush
|
23
|
-
stderr.flush
|
35
|
+
stdout.flush unless stdout.closed?
|
36
|
+
stderr.flush unless stderr.closed?
|
24
37
|
end
|
25
38
|
|
26
39
|
real_exec = method :exec
|
@@ -31,7 +44,6 @@ fork_defn = lambda do |*args|
|
|
31
44
|
$SiB.send :forking_occurred_and_you_are_the_child, event_stream unless result
|
32
45
|
result
|
33
46
|
end
|
34
|
-
|
35
47
|
Kernel.module_eval do
|
36
48
|
private
|
37
49
|
|
@@ -102,7 +102,7 @@ class SeeingIsBelieving
|
|
102
102
|
def wrap_recursive(ast)
|
103
103
|
return wrappings unless ast.kind_of? ::AST::Node
|
104
104
|
case ast.type
|
105
|
-
when :args, :redo, :retry, :alias, :undef, :null_node
|
105
|
+
when :args, :redo, :retry, :alias, :undef, :null_node, :iflipflop, :eflipflop
|
106
106
|
# no op
|
107
107
|
when :defs, :module
|
108
108
|
add_to_wrappings ast
|
data/lib/seeing_is_believing.rb
CHANGED
@@ -16,7 +16,7 @@ class SeeingIsBelieving
|
|
16
16
|
attribute(:encoding) { nil }
|
17
17
|
attribute(:stdin) { "" }
|
18
18
|
attribute(:require_files) { ['seeing_is_believing/the_matrix'] }
|
19
|
-
attribute(:load_path_dirs) { [File.
|
19
|
+
attribute(:load_path_dirs) { [File.realpath(__dir__)] }
|
20
20
|
attribute(:timeout_seconds) { 0 }
|
21
21
|
attribute(:debugger) { Debugger::Null }
|
22
22
|
attribute(:max_line_captures) { Float::INFINITY }
|
@@ -36,7 +36,7 @@ class SeeingIsBelieving
|
|
36
36
|
|
37
37
|
def call
|
38
38
|
@memoized_result ||= Dir.mktmpdir("seeing_is_believing_temp_dir") { |dir|
|
39
|
-
filename
|
39
|
+
filename = options.filename || File.join(dir, 'program.rb')
|
40
40
|
new_program = options.rewrite_code.call @program
|
41
41
|
|
42
42
|
options.debugger.context("REWRITTEN PROGRAM") { new_program }
|
@@ -44,7 +44,7 @@ class SeeingIsBelieving
|
|
44
44
|
EvaluateByMovingFiles.call \
|
45
45
|
new_program,
|
46
46
|
filename,
|
47
|
-
event_handler:
|
47
|
+
event_handler: event_handler(options.debugger, options.event_handler),
|
48
48
|
provided_input: options.stdin,
|
49
49
|
require_files: options.require_files,
|
50
50
|
load_path_dirs: options.load_path_dirs,
|
@@ -58,12 +58,9 @@ class SeeingIsBelieving
|
|
58
58
|
|
59
59
|
private
|
60
60
|
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def debugging_handler
|
66
|
-
return options.event_handler unless options.debugger.enabled?
|
67
|
-
EventStream::Handlers::Debug.new options.debugger, options.event_handler
|
61
|
+
# If we need debugging, wrap a debugging handler around the current handler
|
62
|
+
def event_handler(debugger, current_handler)
|
63
|
+
return current_handler unless debugger.enabled?
|
64
|
+
EventStream::Handlers::Debug.new debugger, current_handler
|
68
65
|
end
|
69
66
|
end
|
data/seeing_is_believing.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.
|
2
|
+
$:.push File.realpath("lib", __dir__)
|
3
3
|
require "seeing_is_believing/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
@@ -19,14 +19,15 @@ 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 "parser",
|
22
|
+
s.add_dependency "parser", ">= 2.3.0.7", "< 3.0"
|
23
|
+
s.add_dependency "childprocess","~> 0.5.9"
|
23
24
|
|
24
|
-
s.add_development_dependency "haiti",
|
25
|
-
s.add_development_dependency "rake",
|
26
|
-
s.add_development_dependency "mrspec",
|
27
|
-
s.add_development_dependency "rspec",
|
28
|
-
s.add_development_dependency "cucumber",
|
29
|
-
s.add_development_dependency "
|
25
|
+
s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
|
26
|
+
s.add_development_dependency "rake", "~> 11.2.2"
|
27
|
+
s.add_development_dependency "mrspec", "~> 0.3.1"
|
28
|
+
s.add_development_dependency "rspec", "~> 3.5"
|
29
|
+
s.add_development_dependency "cucumber", "~> 2.4"
|
30
|
+
s.add_development_dependency "ripper-tags", "~> 0.3"
|
30
31
|
|
31
32
|
s.post_install_message = <<'Omg, frogs <3'.gsub(/(gg+)/) { |capture| "\e[32m#{capture.gsub 'g', '.'}\e[0m" }.gsub("brown", "\e[33m").gsub("off", "\e[0m")
|
32
33
|
.7
|
data/spec/binary/config_spec.rb
CHANGED
@@ -69,6 +69,21 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
shared_examples 'it can extract its argument from conjoined shortflags' do |flag, arg, verify|
|
73
|
+
it 'can be the only item (the argument has no space)' do
|
74
|
+
instance_exec parse(%W[-#{flag}#{arg}]), &verify
|
75
|
+
|
76
|
+
# sanity check the verifier by giving it someting it should fail on
|
77
|
+
expect { instance_exec parse(%W[-#{flag}#{arg}X]), &verify }.to raise_error RSpec::Expectations::ExpectationNotMetError
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'can appear after another flag' do
|
81
|
+
expect( parse(%W[-#{flag}#{arg}] )[:debug]).to eq false
|
82
|
+
expect( parse(%W[-g#{flag}#{arg}] )[:debug]).to eq true
|
83
|
+
instance_exec parse(%W[-g#{flag}#{arg}] ), &verify
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
72
87
|
describe 'parsing from args' do
|
73
88
|
it 'does not mutate the input array' do
|
74
89
|
ary = ['a']
|
@@ -186,6 +201,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
186
201
|
expect(parse(%w[-a ])).to have_error /-a/
|
187
202
|
expect(parse(%w[--as ])).to have_error /--as/
|
188
203
|
end
|
204
|
+
|
205
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'a', 'some-filename.whatever', -> parsed do
|
206
|
+
expect(parsed.lib_options.filename).to eq 'some-filename.whatever'
|
207
|
+
end
|
189
208
|
end
|
190
209
|
|
191
210
|
|
@@ -200,6 +219,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
200
219
|
end
|
201
220
|
|
202
221
|
it_behaves_like 'it requires a positive int argument', ['-D', '--result-length']
|
222
|
+
|
223
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'D', '12', -> parsed do
|
224
|
+
expect(parsed.annotator_options.max_result_length).to eq 12
|
225
|
+
end
|
203
226
|
end
|
204
227
|
|
205
228
|
describe 'annotator_options.max_line_length' do
|
@@ -213,6 +236,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
213
236
|
end
|
214
237
|
|
215
238
|
it_behaves_like 'it requires a positive int argument', ['-d', '--line-length']
|
239
|
+
|
240
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'd', '12', -> parsed do
|
241
|
+
expect(parsed.annotator_options.max_line_length).to eq 12
|
242
|
+
end
|
216
243
|
end
|
217
244
|
|
218
245
|
describe 'lib_options.require_files' do
|
@@ -233,6 +260,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
233
260
|
specify '-r and --require add the filename into the result array' do
|
234
261
|
expect(parse(%w[-r f1 --require f2]).lib_options.require_files).to eq [matrix_file, 'f1', 'f2']
|
235
262
|
end
|
263
|
+
|
264
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'r', 'filename', -> parsed do
|
265
|
+
expect(parsed.lib_options.require_files).to include 'filename'
|
266
|
+
end
|
236
267
|
end
|
237
268
|
|
238
269
|
describe 'print_help? and help_screen' do
|
@@ -284,10 +315,14 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
284
315
|
expect(parse(['--program', 'body'])).to_not have_error /--program/
|
285
316
|
expect(parse(['--program' ])).to have_error /--program/
|
286
317
|
end
|
318
|
+
|
319
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'e', 'some program', -> parsed do
|
320
|
+
expect(parsed.body).to eq 'some program'
|
321
|
+
end
|
287
322
|
end
|
288
323
|
|
289
324
|
describe'lib_options.load_path_dirs' do
|
290
|
-
let(:lib_path) { File.
|
325
|
+
let(:lib_path) { File.realpath '../../lib', __dir__ }
|
291
326
|
|
292
327
|
it 'defaults to sib\'s lib path' do
|
293
328
|
expect(parse([]).lib_options.load_path_dirs).to eq [lib_path]
|
@@ -302,6 +337,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
302
337
|
expect(parse(['-I'])).to have_error /-I\b/
|
303
338
|
expect(parse(['--load-path'])).to have_error /--load-path\b/
|
304
339
|
end
|
340
|
+
|
341
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'I', 'added-path', -> parsed do
|
342
|
+
expect(parsed.lib_options.load_path_dirs).to include 'added-path'
|
343
|
+
end
|
305
344
|
end
|
306
345
|
|
307
346
|
describe 'lib_options.encoding' do
|
@@ -326,6 +365,16 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
326
365
|
expect(parse(['-K'])).to have_error /-K/
|
327
366
|
expect(parse(['--encoding'])).to have_error /--encoding/
|
328
367
|
end
|
368
|
+
|
369
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'K', 'u', -> parsed do
|
370
|
+
expect(parsed.lib_options.encoding).to eq 'u'
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'is deprecated' do
|
374
|
+
assert_deprecated '--encoding', 'u'
|
375
|
+
assert_deprecated '-K', 'u'
|
376
|
+
assert_deprecated '-Ku'
|
377
|
+
end
|
329
378
|
end
|
330
379
|
|
331
380
|
describe '.print_cleaned?' do
|
@@ -368,6 +417,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
368
417
|
end
|
369
418
|
|
370
419
|
it_behaves_like 'it requires a non-negative float or int', ['-t', '--timeout-seconds', '--timeout']
|
420
|
+
|
421
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 't', '123', -> parsed do
|
422
|
+
expect(parsed.lib_options.timeout_seconds).to eq 123
|
423
|
+
end
|
371
424
|
end
|
372
425
|
|
373
426
|
describe 'annotator_options.alignment_strategy' do
|
@@ -403,6 +456,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
403
456
|
expect(parse(['-s', 'file'])).to_not have_error '-s'
|
404
457
|
expect(parse(['-s', 'unknown'])).to have_error '-s', 'expected one of'
|
405
458
|
end
|
459
|
+
|
460
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 's', 'file', -> parsed do
|
461
|
+
expect(parsed.annotator_options.alignment_strategy).to eq align_file
|
462
|
+
end
|
406
463
|
end
|
407
464
|
|
408
465
|
describe 'inherit_exitstatus?' do
|
@@ -499,6 +556,10 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
499
556
|
end
|
500
557
|
|
501
558
|
it_behaves_like 'it requires a positive int argument', ['-n', '--max-line-captures', '--number-of-captures']
|
559
|
+
|
560
|
+
it_behaves_like 'it can extract its argument from conjoined shortflags', 'n', '12', -> parsed do
|
561
|
+
expect(parsed.lib_options.max_line_captures).to eq 12
|
562
|
+
end
|
502
563
|
end
|
503
564
|
|
504
565
|
describe 'result_as_json?' do
|
@@ -580,7 +641,7 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
580
641
|
|
581
642
|
describe '.finalize' do
|
582
643
|
let(:stdin_data) { 'stdin data' }
|
583
|
-
let(:stdin) { object_double $stdin, read: stdin_data }
|
644
|
+
let(:stdin) { object_double $stdin, read: stdin_data, set_encoding: nil }
|
584
645
|
let(:stdout) { object_double $stdout }
|
585
646
|
let(:stderr) { object_double $stderr, :tty? => true }
|
586
647
|
|
@@ -592,7 +653,7 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
592
653
|
before do
|
593
654
|
allow(file_class).to receive(:exist?).with(existing_filename).and_return(true)
|
594
655
|
allow(file_class).to receive(:exist?).with(nonexisting_filename).and_return(false)
|
595
|
-
allow(file_class).to receive(:read).with(existing_filename).and_return(file_body)
|
656
|
+
allow(file_class).to receive(:read).with(existing_filename, any_args).and_return(file_body)
|
596
657
|
end
|
597
658
|
|
598
659
|
def call(attrs={})
|
@@ -715,7 +776,7 @@ RSpec.describe SeeingIsBelieving::Binary::Config do
|
|
715
776
|
end
|
716
777
|
|
717
778
|
context 'when debug? is a string' do
|
718
|
-
let(:proving_grounds_dir) { File.
|
779
|
+
let(:proving_grounds_dir) { File.realdirpath '../../proving_grounds', __dir__ }
|
719
780
|
let(:path) { File.join proving_grounds_dir, 'test.log' }
|
720
781
|
before { Dir.mkdir proving_grounds_dir unless Dir.exist? proving_grounds_dir }
|
721
782
|
|
data/spec/binary/engine_spec.rb
CHANGED
@@ -4,9 +4,10 @@ require 'spec_helper'
|
|
4
4
|
require 'seeing_is_believing/evaluate_by_moving_files'
|
5
5
|
require 'seeing_is_believing/event_stream/handlers/update_result'
|
6
6
|
require 'fileutils'
|
7
|
+
require 'childprocess'
|
7
8
|
|
8
9
|
RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
9
|
-
let(:filedir) { File.
|
10
|
+
let(:filedir) { File.realdirpath '../proving_grounds', __dir__ }
|
10
11
|
let(:filename) { File.join filedir, 'some_filename' }
|
11
12
|
|
12
13
|
before { FileUtils.mkdir_p filedir }
|
@@ -143,15 +144,40 @@ RSpec.describe SeeingIsBelieving::EvaluateByMovingFiles do
|
|
143
144
|
end
|
144
145
|
|
145
146
|
it 'can set a timeout, which interrupts the process group and then waits for the events to finish' do
|
146
|
-
|
147
|
-
|
148
|
-
|
147
|
+
pre = Time.now
|
148
|
+
result = invoke <<-RUBY, timeout_seconds: 0.5
|
149
|
+
child_pid = spawn 'ruby', '-e', 'sleep' # child makes a grandchild which sleeps
|
150
|
+
puts Process.pid, child_pid # print ids so we can check they got killed
|
151
|
+
sleep # child sleeps
|
152
|
+
RUBY
|
153
|
+
post = Time.now
|
149
154
|
expect(result.timeout?).to eq true
|
150
|
-
expect(result.timeout_seconds).to eq
|
155
|
+
expect(result.timeout_seconds).to eq 0.5
|
156
|
+
expect(post - pre).to be > 0.5
|
157
|
+
child_id, grandchild_id, *rest = result.stdout.lines
|
158
|
+
expect(child_id).to match /^\d+$/
|
159
|
+
expect(grandchild_id).to match /^\d+$/
|
160
|
+
expect(rest).to be_empty
|
161
|
+
expect { Process.wait child_id.to_i } .to raise_error /no.*processes/i
|
162
|
+
expect { Process.wait grandchild_id.to_i } .to raise_error /no.*processes/i
|
151
163
|
end
|
152
164
|
|
153
165
|
it 'raises an ArgumentError if given arguments it doesn\'t know' do
|
154
166
|
expect { invoke '1', watisthis: :idontknow }
|
155
167
|
.to raise_error ArgumentError, /watisthis/
|
156
168
|
end
|
169
|
+
|
170
|
+
it 'doesn\'t explode or do anything else obnoxious when the input stream is closed' do
|
171
|
+
infinite_string = Object.new
|
172
|
+
def infinite_string.each_char
|
173
|
+
loop { yield 'c' }
|
174
|
+
end
|
175
|
+
result = nil
|
176
|
+
expect {
|
177
|
+
result = invoke '$stdin.close', provided_input: infinite_string
|
178
|
+
}.to_not output.to_stderr
|
179
|
+
expect(result.exitstatus).to eq 0
|
180
|
+
expect(result.stderr).to be_empty
|
181
|
+
expect(result.stdout).to be_empty
|
182
|
+
end
|
157
183
|
end
|
data/spec/event_stream_spec.rb
CHANGED
@@ -24,9 +24,9 @@ module SeeingIsBelieving::EventStream
|
|
24
24
|
end
|
25
25
|
|
26
26
|
before do
|
27
|
-
self.eventstream_consumer, self.eventstream_producer = IO.pipe
|
28
|
-
self.stdout_consumer, self.stdout_producer = IO.pipe
|
29
|
-
self.stderr_consumer, self.stderr_producer = IO.pipe
|
27
|
+
self.eventstream_consumer, self.eventstream_producer = IO.pipe("utf-8")
|
28
|
+
self.stdout_consumer, self.stdout_producer = IO.pipe("utf-8")
|
29
|
+
self.stderr_consumer, self.stderr_producer = IO.pipe("utf-8")
|
30
30
|
|
31
31
|
self.producer = SeeingIsBelieving::EventStream::Producer.new eventstream_producer
|
32
32
|
self.consumer = SeeingIsBelieving::EventStream::Consumer.new \
|
@@ -42,9 +42,8 @@ module SeeingIsBelieving::EventStream
|
|
42
42
|
|
43
43
|
describe 'emitting an event' do
|
44
44
|
def has_message?(io)
|
45
|
-
|
46
|
-
|
47
|
-
return false
|
45
|
+
readables, * = IO.select([io], [], [], 0.1) # 0.1 is the timeout
|
46
|
+
readables.to_a.any? # when it times out, IO.select may return nil...
|
48
47
|
end
|
49
48
|
|
50
49
|
it 'writes its events to the event stream' do
|
@@ -592,6 +591,15 @@ module SeeingIsBelieving::EventStream
|
|
592
591
|
expect(consumer.call).to eq Events::Exitstatus.new(value: 92)
|
593
592
|
end
|
594
593
|
|
594
|
+
it 'translates missing statusses to 1 (eg this happens on my machine when the program segfaults, see #100)' do
|
595
|
+
# I'm not totally sure this is the right thing for it to do, but a segfault is the only way
|
596
|
+
# I know of to invoke this situation, and a segfault is printable, so until I get some info
|
597
|
+
# that proves this is the wrong thing to do, we're just going to give it a normal exit status
|
598
|
+
# since that's the easiest thing to do, and it's more correct in this one case.
|
599
|
+
consumer.process_exitstatus nil
|
600
|
+
expect(consumer.call).to eq Events::Exitstatus.new(value: 1)
|
601
|
+
end
|
602
|
+
|
595
603
|
it 'emits a Finished event when all streams are closed and it has an exit status' do
|
596
604
|
consumer.process_exitstatus 1
|
597
605
|
close_streams eventstream_producer, stdout_producer, stderr_producer
|