seeing_is_believing 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/features/flags.feature +39 -0
- data/features/regression.feature +154 -0
- data/features/xmpfilter-style.feature +57 -0
- data/lib/seeing_is_believing/binary/annotate_every_line.rb +11 -4
- data/lib/seeing_is_believing/binary/annotate_marked_lines.rb +11 -5
- data/lib/seeing_is_believing/binary/config.rb +9 -0
- data/lib/seeing_is_believing/binary/data_structures.rb +1 -0
- data/lib/seeing_is_believing/binary/interline_align.rb +57 -0
- data/lib/seeing_is_believing/customize_pp.rb +5 -0
- data/lib/seeing_is_believing/event_stream/consumer.rb +39 -43
- data/lib/seeing_is_believing/event_stream/producer.rb +24 -31
- data/lib/seeing_is_believing/safe.rb +93 -39
- data/lib/seeing_is_believing/the_matrix.rb +10 -10
- data/lib/seeing_is_believing/version.rb +1 -1
- data/lib/seeing_is_believing/wrap_expressions.rb +24 -5
- data/spec/binary/config_spec.rb +17 -2
- data/spec/event_stream_spec.rb +1 -0
- data/spec/seeing_is_believing_spec.rb +58 -53
- data/spec/spec_helper.rb +22 -0
- data/spec/spec_helper_spec.rb +16 -0
- data/spec/wrap_expressions_spec.rb +35 -0
- metadata +7 -3
@@ -56,15 +56,7 @@ class SeeingIsBelieving
|
|
56
56
|
rescue EncodingError
|
57
57
|
str = str.force_encoding(Encoding::UTF_8)
|
58
58
|
end
|
59
|
-
|
60
|
-
# basically reimplement scrub, b/c it's not implemented on 1.9.3
|
61
|
-
str.each_char.inject("") do |new_str, char|
|
62
|
-
if char.valid_encoding?
|
63
|
-
new_str << char
|
64
|
-
else
|
65
|
-
new_str << '�'
|
66
|
-
end
|
67
|
-
end
|
59
|
+
str.scrub '�'
|
68
60
|
end
|
69
61
|
|
70
62
|
def initialize(streams)
|
@@ -74,39 +66,40 @@ class SeeingIsBelieving
|
|
74
66
|
event_stream = streams.fetch :events
|
75
67
|
stdout_stream = streams.fetch :stdout
|
76
68
|
stderr_stream = streams.fetch :stderr
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
69
|
+
self.threads = [
|
70
|
+
Thread.new do
|
71
|
+
begin
|
72
|
+
stdout_stream.each_line { |line| queue << Events::Stdout.new(value: line) }
|
73
|
+
queue << Events::StdoutClosed.new(side: :producer)
|
74
|
+
rescue IOError
|
75
|
+
queue << Events::StdoutClosed.new(side: :consumer)
|
76
|
+
ensure
|
77
|
+
queue << lambda { finish_criteria.stdout_thread_finished! }
|
78
|
+
end
|
79
|
+
end,
|
80
|
+
|
81
|
+
Thread.new do
|
82
|
+
begin
|
83
|
+
stderr_stream.each_line { |line| queue << Events::Stderr.new(value: line) }
|
84
|
+
queue << Events::StderrClosed.new(side: :producer)
|
85
|
+
rescue IOError
|
86
|
+
queue << Events::StderrClosed.new(side: :consumer)
|
87
|
+
ensure
|
88
|
+
queue << lambda { finish_criteria.stderr_thread_finished! }
|
89
|
+
end
|
90
|
+
end,
|
91
|
+
|
92
|
+
Thread.new do
|
93
|
+
begin
|
94
|
+
event_stream.each_line { |line| queue << line }
|
95
|
+
queue << Events::EventStreamClosed.new(side: :producer)
|
96
|
+
rescue IOError
|
97
|
+
queue << Events::EventStreamClosed.new(side: :consumer)
|
98
|
+
ensure
|
99
|
+
queue << lambda { finish_criteria.event_thread_finished! }
|
100
|
+
end
|
101
|
+
end,
|
102
|
+
]
|
110
103
|
end
|
111
104
|
|
112
105
|
def call(n=1)
|
@@ -135,10 +128,13 @@ class SeeingIsBelieving
|
|
135
128
|
}
|
136
129
|
end
|
137
130
|
|
131
|
+
def join
|
132
|
+
threads.each(&:join)
|
133
|
+
end
|
138
134
|
|
139
135
|
private
|
140
136
|
|
141
|
-
attr_accessor :queue, :finish_criteria
|
137
|
+
attr_accessor :queue, :finish_criteria, :threads
|
142
138
|
|
143
139
|
def next_event
|
144
140
|
raise NoMoreEvents if @finished
|
@@ -1,29 +1,27 @@
|
|
1
|
-
require 'seeing_is_believing/event_stream/events'
|
2
1
|
require 'seeing_is_believing/safe'
|
3
|
-
require '
|
2
|
+
require 'seeing_is_believing/event_stream/events'
|
3
|
+
require 'thread' # <-- do we still need this?
|
4
|
+
|
5
|
+
using SeeingIsBelieving::Safe
|
4
6
|
|
5
7
|
class SeeingIsBelieving
|
6
8
|
module EventStream
|
7
9
|
class Producer
|
8
10
|
module NullQueue
|
9
11
|
extend self
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# find a way to test this situation?
|
12
|
+
Queue.instance_methods.each do |name|
|
13
|
+
define_method(name) { |*| }
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
17
|
attr_accessor :max_line_captures, :filename
|
17
18
|
|
18
19
|
def initialize(resultstream)
|
19
|
-
resultstream = Safe::Stream[resultstream]
|
20
20
|
self.filename = nil
|
21
21
|
self.max_line_captures = Float::INFINITY
|
22
22
|
self.recorded_results = []
|
23
|
-
self.queue =
|
24
|
-
self.producer_thread =
|
25
|
-
build_producer_thread(resultstream)
|
26
|
-
]
|
23
|
+
self.queue = Queue.new
|
24
|
+
self.producer_thread = build_producer_thread(resultstream)
|
27
25
|
end
|
28
26
|
|
29
27
|
attr_reader :version
|
@@ -45,7 +43,7 @@ class SeeingIsBelieving
|
|
45
43
|
StackErrors = [SystemStackError]
|
46
44
|
StackErrors << Java::JavaLang::StackOverflowError if defined?(RUBY_PLATFORM) && RUBY_PLATFORM == 'java'
|
47
45
|
def record_result(type, line_number, value)
|
48
|
-
counts = recorded_results[line_number] ||=
|
46
|
+
counts = recorded_results[line_number] ||= Hash.new(0)
|
49
47
|
count = counts[type]
|
50
48
|
recorded_results[line_number][type] = count.next
|
51
49
|
if count < max_line_captures
|
@@ -64,33 +62,30 @@ class SeeingIsBelieving
|
|
64
62
|
rescue Exception
|
65
63
|
inspected = "#<no inspect available>"
|
66
64
|
end
|
67
|
-
queue << "result #{line_number} #{type} #{to_string_token inspected}"
|
65
|
+
queue << "result #{line_number.to_s} #{type.to_s} #{to_string_token inspected}"
|
68
66
|
elsif count == max_line_captures
|
69
|
-
queue << "maxed_result #{line_number} #{type}"
|
67
|
+
queue << "maxed_result #{line_number.to_s} #{type.to_s}"
|
70
68
|
end
|
71
69
|
value
|
72
70
|
end
|
73
71
|
|
74
72
|
# records the exception, returns the exitstatus for that exception
|
75
73
|
def record_exception(line_number, exception)
|
76
|
-
return exception.status if SystemExit === exception
|
77
|
-
exception = Safe::Exception[exception]
|
74
|
+
return exception.status if SystemExit === exception # TODO === is not in the list
|
78
75
|
if !line_number && filename
|
79
|
-
begin line_number = exception.backtrace.grep(/#{filename}/).first[/:\d+/][1..-1].to_i
|
76
|
+
begin line_number = exception.backtrace.grep(/#{filename.to_s}/).first[/:\d+/][1..-1].to_i
|
80
77
|
rescue NoMethodError
|
81
78
|
end
|
82
79
|
end
|
83
80
|
line_number ||= -1
|
84
|
-
queue <<
|
81
|
+
queue << [
|
85
82
|
"exception",
|
86
|
-
|
83
|
+
line_number.to_s,
|
87
84
|
to_string_token(exception.class.name),
|
88
85
|
to_string_token(exception.message),
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
*Safe::Array[exception.backtrace].map { |line| to_string_token line }
|
93
|
-
]].join(" ")
|
86
|
+
exception.backtrace.size.to_s,
|
87
|
+
*exception.backtrace.map { |line| to_string_token line }
|
88
|
+
].join(" ")
|
94
89
|
1 # exit status
|
95
90
|
end
|
96
91
|
|
@@ -108,7 +103,7 @@ class SeeingIsBelieving
|
|
108
103
|
end
|
109
104
|
|
110
105
|
def finish!
|
111
|
-
queue << :break # note that consumer will continue reading until stream is closed
|
106
|
+
queue << :break # note that consumer will continue reading until stream is closed, which is not the responsibility of the producer
|
112
107
|
producer_thread.join
|
113
108
|
end
|
114
109
|
|
@@ -118,17 +113,17 @@ class SeeingIsBelieving
|
|
118
113
|
|
119
114
|
# for a consideration of many different ways of doing this, see 5633064
|
120
115
|
def to_string_token(string)
|
121
|
-
|
116
|
+
[Marshal.dump(string.to_s)].pack('m0')
|
122
117
|
end
|
123
118
|
|
124
119
|
def build_producer_thread(resultstream)
|
125
120
|
::Thread.new {
|
126
|
-
|
121
|
+
Thread.current.abort_on_exception = true
|
127
122
|
begin
|
128
123
|
resultstream.sync = true
|
129
124
|
loop do
|
130
125
|
to_publish = queue.shift
|
131
|
-
break if
|
126
|
+
break if :break == to_publish
|
132
127
|
resultstream << (to_publish << "\n")
|
133
128
|
end
|
134
129
|
rescue IOError, Errno::EPIPE
|
@@ -147,9 +142,7 @@ class SeeingIsBelieving
|
|
147
142
|
loop { break if queue.shift == :fork }
|
148
143
|
|
149
144
|
# recreate the thread since forking in Ruby kills threads
|
150
|
-
@producer_thread =
|
151
|
-
build_producer_thread(resultstream)
|
152
|
-
]
|
145
|
+
@producer_thread = build_producer_thread(resultstream)
|
153
146
|
end
|
154
147
|
|
155
148
|
end
|
@@ -1,43 +1,97 @@
|
|
1
|
+
# require this before anything else, b/c it expects the world to be sane when it is loaded
|
1
2
|
class SeeingIsBelieving
|
2
3
|
module Safe
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
4
|
+
refine Class do
|
5
|
+
alias === ===
|
6
|
+
end
|
7
|
+
|
8
|
+
refine Queue do
|
9
|
+
alias << <<
|
10
|
+
alias shift shift
|
11
|
+
alias clear clear
|
12
|
+
end
|
13
|
+
|
14
|
+
refine IO do
|
15
|
+
alias sync= sync=
|
16
|
+
alias << <<
|
17
|
+
alias flush flush
|
18
|
+
alias close close
|
19
|
+
end
|
20
|
+
|
21
|
+
refine Symbol do
|
22
|
+
alias == ==
|
23
|
+
alias to_s to_s
|
24
|
+
alias inspect inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
refine Symbol.singleton_class do
|
28
|
+
alias define_method define_method
|
29
|
+
alias class_eval class_eval
|
30
|
+
end
|
31
|
+
|
32
|
+
refine String do
|
33
|
+
alias == ==
|
34
|
+
alias to_s to_s
|
35
|
+
alias to_str to_str
|
36
|
+
end
|
37
|
+
|
38
|
+
refine Fixnum do
|
39
|
+
alias to_s to_s
|
40
|
+
alias next next
|
41
|
+
alias < <
|
42
|
+
end
|
43
|
+
|
44
|
+
refine Array do
|
45
|
+
alias pack pack
|
46
|
+
alias map map
|
47
|
+
alias size size
|
48
|
+
alias join join
|
49
|
+
alias [] []
|
50
|
+
alias []= []=
|
51
|
+
end
|
52
|
+
|
53
|
+
refine Hash do
|
54
|
+
alias [] []
|
55
|
+
alias []= []=
|
56
|
+
end
|
57
|
+
|
58
|
+
refine Hash.singleton_class do
|
59
|
+
alias new new
|
60
|
+
end
|
61
|
+
|
62
|
+
refine Marshal.singleton_class do
|
63
|
+
alias dump dump
|
64
|
+
end
|
65
|
+
|
66
|
+
refine Exception do
|
67
|
+
alias message message
|
68
|
+
alias backtrace backtrace
|
69
|
+
alias class class
|
70
|
+
end
|
71
|
+
|
72
|
+
refine Exception.singleton_class do
|
73
|
+
alias define_method define_method
|
74
|
+
alias class_eval class_eval
|
75
|
+
end
|
76
|
+
|
77
|
+
refine Thread do
|
78
|
+
alias join join
|
79
|
+
end
|
80
|
+
|
81
|
+
refine Thread.singleton_class do
|
82
|
+
alias current current
|
83
|
+
end
|
84
|
+
|
85
|
+
refine Method do
|
86
|
+
alias call call
|
87
|
+
end
|
88
|
+
|
89
|
+
refine Proc do
|
90
|
+
alias call call
|
91
|
+
end
|
92
|
+
|
93
|
+
refine Object do
|
94
|
+
alias block_given? block_given?
|
95
|
+
end
|
42
96
|
end
|
43
97
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
-
require_relative 'version'
|
2
1
|
require_relative 'safe'
|
2
|
+
require_relative 'version'
|
3
3
|
require_relative 'event_stream/producer'
|
4
4
|
|
5
|
+
using SeeingIsBelieving::Safe
|
6
|
+
|
5
7
|
sib_vars = Marshal.load ENV["SIB_VARIABLES.MARSHAL.B64"].unpack('m0').first
|
6
8
|
event_stream = IO.open sib_vars.fetch(:event_stream_fd), "w"
|
7
9
|
$SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
|
@@ -12,12 +14,11 @@ $SiB.record_num_lines sib_vars.fetch(:num_lines)
|
|
12
14
|
$SiB.record_max_line_captures sib_vars.fetch(:max_line_captures)
|
13
15
|
|
14
16
|
STDOUT.sync = true
|
15
|
-
stdout =
|
16
|
-
stderr = SeeingIsBelieving::Safe::Stream[STDERR]
|
17
|
+
stdout, stderr = STDOUT, STDERR
|
17
18
|
|
18
19
|
finish = lambda do
|
19
20
|
$SiB.finish!
|
20
|
-
|
21
|
+
event_stream.close
|
21
22
|
stdout.flush
|
22
23
|
stderr.flush
|
23
24
|
end
|
@@ -56,16 +57,15 @@ Kernel.define_singleton_method :fork, &fork_defn
|
|
56
57
|
Process.define_singleton_method :fork, &fork_defn
|
57
58
|
|
58
59
|
|
59
|
-
# Some things need to
|
60
|
+
# Some things need to be recorded and readded as they are called from Ruby C code and it blows up in really difficult to dianose ways -.-
|
60
61
|
symbol_to_s = Symbol.instance_method(:to_s)
|
61
62
|
exception_message = Exception.instance_method(:message)
|
62
|
-
|
63
|
+
exception_backtrace = Exception.instance_method(:backtrace)
|
63
64
|
|
64
65
|
at_exit do
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
Exception.class_eval { define_method :message, exception_message }
|
67
|
+
Exception.class_eval { define_method :backtrace, exception_backtrace }
|
68
|
+
Symbol.class_eval { define_method :to_s, symbol_to_s }
|
69
69
|
exitstatus = ($! ? $SiB.record_exception(nil, $!) : 0)
|
70
70
|
finish.call
|
71
71
|
real_exit_bang.call(exitstatus) # clears exceptions so they don't print to stderr and change the processes actual exit status (we recorded what it should be)
|
@@ -93,6 +93,12 @@ class SeeingIsBelieving
|
|
93
93
|
.each { |child| wrap_recursive child }
|
94
94
|
end
|
95
95
|
|
96
|
+
def add_interpolations_in(ast)
|
97
|
+
ast.children
|
98
|
+
.select { |child| child.type == :begin }
|
99
|
+
.each { |child| add_children child }
|
100
|
+
end
|
101
|
+
|
96
102
|
def wrap_recursive(ast)
|
97
103
|
return wrappings unless ast.kind_of? ::AST::Node
|
98
104
|
case ast.type
|
@@ -128,7 +134,22 @@ class SeeingIsBelieving
|
|
128
134
|
when :array
|
129
135
|
add_to_wrappings ast
|
130
136
|
the_begin = ast.location.begin
|
131
|
-
|
137
|
+
if !the_begin
|
138
|
+
# uhhhh, idk, nothing seems to hit this branch (at least in its spec)
|
139
|
+
# maybe this is 'a = 1,2,3'? (I'd try it out, but have to call the folks)
|
140
|
+
elsif the_begin.source !~ /\A%/
|
141
|
+
# normal array
|
142
|
+
add_children ast
|
143
|
+
elsif the_begin.source =~ /\A%/
|
144
|
+
# array of literals
|
145
|
+
|
146
|
+
ast.children.each do |child|
|
147
|
+
t = child.type
|
148
|
+
if t == :dsym || t == :dstr
|
149
|
+
add_interpolations_in child
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
132
153
|
when :block
|
133
154
|
add_to_wrappings ast
|
134
155
|
|
@@ -205,11 +226,9 @@ class SeeingIsBelieving
|
|
205
226
|
when :str
|
206
227
|
add_to_wrappings ast
|
207
228
|
|
208
|
-
when :dstr, :
|
229
|
+
when :regexp, :dstr, :xstr, :dsym
|
209
230
|
add_to_wrappings ast
|
210
|
-
ast
|
211
|
-
.select { |child| child.type == :begin }
|
212
|
-
.each { |child| add_children child }
|
231
|
+
add_interpolations_in ast
|
213
232
|
|
214
233
|
when :hash
|
215
234
|
# method arguments might not have braces around them
|