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