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
@@ -3,7 +3,7 @@ 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, :
|
6
|
+
attr_accessor :stdout, :stderr, :exitstatus, :max_line_captures, :exception, :num_lines, :sib_version, :ruby_version, :filename
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
self.stdout = ''
|
@@ -52,8 +52,25 @@ class SeeingIsBelieving
|
|
52
52
|
"#<SIB::Result #{variables.join "\n "}>"
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
56
|
-
@
|
55
|
+
def max_line_captures
|
56
|
+
@max_line_captures || Float::INFINITY
|
57
|
+
end
|
58
|
+
|
59
|
+
def as_json
|
60
|
+
ex = has_exception? && {
|
61
|
+
line_number_in_this_file: exception.line_number,
|
62
|
+
class_name: exception.class_name,
|
63
|
+
message: exception.message,
|
64
|
+
backtrace: exception.backtrace,
|
65
|
+
}
|
66
|
+
|
67
|
+
{ stdout: stdout,
|
68
|
+
stderr: stderr,
|
69
|
+
exitstatus: exitstatus,
|
70
|
+
exception: ex,
|
71
|
+
lines: each.with_object(Hash.new)
|
72
|
+
.with_index(1) { |(result, hash), line_number| hash[line_number] = result },
|
73
|
+
}
|
57
74
|
end
|
58
75
|
|
59
76
|
private
|
@@ -1,16 +1,16 @@
|
|
1
|
-
# WARNING: DO NOT REQUIRE THIS FILE, IT WILL FUCK YOU UP!!!!!!
|
2
|
-
|
3
|
-
# READ THIS IF YOU WANT TO USE YOUR OWN MATRIX FILE:
|
4
|
-
# https://github.com/JoshCheek/seeing_is_believing/issues/24
|
5
|
-
#
|
6
|
-
# (or if you want to understand why we do the pipe dance)
|
7
|
-
|
8
1
|
require_relative 'version'
|
9
2
|
require_relative 'event_stream/producer'
|
10
3
|
|
11
|
-
|
4
|
+
sib_vars = Marshal.load ENV["SIB_VARIABLES.MARSHAL.B64"].unpack('m0').first
|
5
|
+
event_stream = IO.open sib_vars.fetch(:event_stream_fd), "w"
|
12
6
|
$SiB = SeeingIsBelieving::EventStream::Producer.new(event_stream)
|
7
|
+
$SiB.record_ruby_version RUBY_VERSION
|
8
|
+
$SiB.record_sib_version SeeingIsBelieving::VERSION
|
9
|
+
$SiB.record_filename sib_vars.fetch(:filename)
|
10
|
+
$SiB.record_num_lines sib_vars.fetch(:num_lines)
|
11
|
+
$SiB.record_max_line_captures sib_vars.fetch(:max_line_captures)
|
13
12
|
|
13
|
+
STDOUT.sync = true
|
14
14
|
stdout, stderr = STDOUT, STDERR
|
15
15
|
finish = lambda do
|
16
16
|
$SiB.finish!
|
@@ -19,17 +19,25 @@ finish = lambda do
|
|
19
19
|
stderr.flush
|
20
20
|
end
|
21
21
|
|
22
|
-
real_exec
|
22
|
+
real_exec = method :exec
|
23
|
+
real_exit_bang = method :exit!
|
23
24
|
Kernel.module_eval do
|
24
25
|
private
|
25
|
-
|
26
|
+
|
27
|
+
define_method :exec do |*args, &block|
|
28
|
+
$SiB.record_exec(args)
|
26
29
|
finish.call
|
27
30
|
real_exec.call(*args, &block)
|
28
31
|
end
|
32
|
+
|
33
|
+
define_method :exit! do |status=false|
|
34
|
+
finish.call
|
35
|
+
real_exit_bang.call(status)
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
at_exit do
|
32
|
-
$SiB.record_exception
|
40
|
+
exitstatus = ($! ? $SiB.record_exception(nil, $!) : 0)
|
33
41
|
finish.call
|
34
|
-
|
42
|
+
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)
|
35
43
|
end
|
@@ -1,44 +1,39 @@
|
|
1
|
-
require 'seeing_is_believing/
|
1
|
+
require 'seeing_is_believing/code'
|
2
2
|
|
3
3
|
# comprehensive list of syntaxes that can come up
|
4
4
|
# https://github.com/whitequark/parser/blob/master/doc/AST_FORMAT.md
|
5
5
|
class SeeingIsBelieving
|
6
6
|
class WrapExpressions
|
7
7
|
|
8
|
-
include ParserHelpers
|
9
|
-
|
10
8
|
def self.call(program, wrappings)
|
11
9
|
new(program, wrappings).call
|
12
10
|
end
|
13
11
|
|
14
12
|
def initialize(program, wrappings)
|
15
|
-
self.
|
16
|
-
self.
|
17
|
-
self.after_all = wrappings.fetch :after_all, -> { ''.freeze }
|
13
|
+
self.before_all = wrappings.fetch :before_all, -> { '' }
|
14
|
+
self.after_all = wrappings.fetch :after_all, -> { '' }
|
18
15
|
self.before_each = wrappings.fetch :before_each, -> * { '' }
|
19
16
|
self.after_each = wrappings.fetch :after_each, -> * { '' }
|
20
|
-
self.buffer, parser, self.rewriter = initialize_parser(program, 'program-without-annotations')
|
21
|
-
self.root = parser.parse buffer
|
22
17
|
self.wrappings = {}
|
23
|
-
|
24
|
-
raise
|
18
|
+
self.code = Code.new(program, 'program-without-annotations')
|
19
|
+
code.syntax.valid? || raise(::SyntaxError, code.syntax.error_message)
|
25
20
|
end
|
26
21
|
|
27
22
|
def call
|
28
23
|
@called ||= begin
|
29
|
-
wrap_recursive
|
24
|
+
wrap_recursive code.root
|
30
25
|
|
31
26
|
rewriter.insert_before root_range, before_all.call
|
32
27
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rewriter.
|
28
|
+
wrappings.each do |line_num, (range, last_col, meta)|
|
29
|
+
rewriter.insert_before range, before_each.call(line_num)
|
30
|
+
case meta
|
31
|
+
when :total_fucking_failure
|
32
|
+
rewriter.replace range, '.....TOTAL FUCKING FAILURE!.....'
|
33
|
+
when :match_current_line
|
34
|
+
rewriter.insert_before range, '~' # Regexp#~
|
40
35
|
end
|
41
|
-
range
|
36
|
+
rewriter.insert_after range, after_each.call(line_num)
|
42
37
|
end
|
43
38
|
|
44
39
|
rewriter.insert_after root_range, after_all_text
|
@@ -48,14 +43,14 @@ class SeeingIsBelieving
|
|
48
43
|
|
49
44
|
private
|
50
45
|
|
51
|
-
attr_accessor :
|
46
|
+
attr_accessor :before_all, :after_all, :before_each, :after_each
|
47
|
+
attr_accessor :code, :wrappings
|
48
|
+
|
49
|
+
def buffer() code.buffer end
|
50
|
+
def rewriter() code.rewriter end
|
52
51
|
|
53
52
|
def root_range
|
54
|
-
|
55
|
-
root.location.expression
|
56
|
-
else
|
57
|
-
Parser::Source::Range.new buffer, 0, 0
|
58
|
-
end
|
53
|
+
code.root.location.expression
|
59
54
|
end
|
60
55
|
|
61
56
|
def after_all_text
|
@@ -72,7 +67,15 @@ class SeeingIsBelieving
|
|
72
67
|
|
73
68
|
def add_to_wrappings(range_or_ast, meta=nil)
|
74
69
|
range = range_or_ast
|
75
|
-
|
70
|
+
if range.kind_of? ::AST::Node
|
71
|
+
location = range_or_ast.location
|
72
|
+
# __ENCODING__ becomes: (const (const nil :Encoding) :UTF_8)
|
73
|
+
# Where the inner const doesn't have a location because it doesn't correspond to a real token.
|
74
|
+
# There is not currently a way to turn this off, but it would be nice to have one like __LINE__ does
|
75
|
+
# https://github.com/whitequark/parser/blob/e2249d7051b1adb6979139928e14a81bc62f566e/lib/parser/builders/default.rb#L333-343
|
76
|
+
return unless location.respond_to? :expression
|
77
|
+
range = location.expression
|
78
|
+
end
|
76
79
|
line, col = buffer.decompose_position range.end_pos
|
77
80
|
_, prev_col, _ = wrappings[line]
|
78
81
|
wrappings[line] = (!wrappings[line] || prev_col < col ? [range, col, meta] : wrappings[line] )
|
@@ -83,33 +86,31 @@ class SeeingIsBelieving
|
|
83
86
|
.each { |child| wrap_recursive child }
|
84
87
|
end
|
85
88
|
|
86
|
-
|
87
|
-
# and add_wrappings is actually add_wrapping?
|
88
|
-
def wrap_recursive(ast=root)
|
89
|
+
def wrap_recursive(ast)
|
89
90
|
return wrappings unless ast.kind_of? ::AST::Node
|
90
91
|
case ast.type
|
91
|
-
when :args, :redo, :retry, :alias, :undef, :
|
92
|
+
when :args, :redo, :retry, :alias, :undef, :null_node
|
92
93
|
# no op
|
93
|
-
when :defs
|
94
|
+
when :defs, :class, :module
|
94
95
|
add_to_wrappings ast
|
95
96
|
add_children ast, true
|
96
|
-
when :rescue, :ensure, :return, :break, :next
|
97
|
+
when :rescue, :ensure, :return, :break, :next, :splat, :kwsplat
|
97
98
|
add_children ast
|
98
99
|
when :if
|
99
100
|
if ast.location.kind_of? Parser::Source::Map::Ternary
|
100
|
-
add_to_wrappings ast unless ast.children.any? { |child| void_value? child }
|
101
|
+
add_to_wrappings ast unless ast.children.any? { |child| code.void_value? child }
|
101
102
|
add_children ast
|
102
103
|
else
|
103
|
-
keyword = ast.location.keyword.source
|
104
|
-
if (keyword == 'if' || keyword == 'unless') && ast.children.none? { |child| void_value? child }
|
104
|
+
keyword = ast.location.keyword.source # if, elsif, unless, else, ....
|
105
|
+
if (keyword == 'if' || keyword == 'unless') && ast.children.none? { |child| code.void_value? child }
|
105
106
|
add_to_wrappings ast
|
106
107
|
end
|
107
108
|
add_children ast
|
108
109
|
end
|
109
|
-
when :when, :pair
|
110
|
+
when :when, :pair # pair is 1=>2
|
110
111
|
wrap_recursive ast.children.last
|
111
112
|
when :resbody
|
112
|
-
|
113
|
+
_exception_type, _variable_name, body = ast.children
|
113
114
|
wrap_recursive body
|
114
115
|
when :array
|
115
116
|
add_to_wrappings ast
|
@@ -154,8 +155,8 @@ class SeeingIsBelieving
|
|
154
155
|
add_children ast, true
|
155
156
|
else
|
156
157
|
begin_pos = ast.location.expression.begin_pos
|
157
|
-
end_pos =
|
158
|
-
range =
|
158
|
+
end_pos = array.children.last.location.expression.end_pos
|
159
|
+
range = code.range_for(begin_pos, end_pos)
|
159
160
|
add_to_wrappings range
|
160
161
|
add_children ast.children.last
|
161
162
|
end
|
@@ -168,95 +169,28 @@ class SeeingIsBelieving
|
|
168
169
|
:and_asgn, # a &&= b
|
169
170
|
:op_asgn # a += b, a -= b, a *= b, etc
|
170
171
|
|
171
|
-
#
|
172
|
-
# we
|
172
|
+
# a=b gets wrapped <a=b>
|
173
|
+
# but we don't wrap the lvar in `for a in range`
|
173
174
|
if ast.children.last.kind_of? ::AST::Node
|
174
175
|
begin_pos = ast.location.expression.begin_pos
|
175
|
-
end_pos =
|
176
|
-
range =
|
176
|
+
end_pos = ast.children.last.location.expression.end_pos
|
177
|
+
range = code.range_for(begin_pos, end_pos)
|
177
178
|
add_to_wrappings range
|
178
179
|
add_children ast, true
|
179
180
|
end
|
180
181
|
when :send
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
# so we check for this case, that way we can construct the correct range instead
|
185
|
-
range = ast.location.expression
|
186
|
-
|
187
|
-
# first two children: target, message, so we want the last child only if it is an argument
|
188
|
-
children = ast.children
|
189
|
-
target = children[0]
|
190
|
-
message = children[1]
|
191
|
-
last_arg = children.size > 2 ? children[-1] : nil
|
192
|
-
|
193
|
-
|
194
|
-
# last arg is a heredoc, use the closing paren, or the end of the first line of the heredoc
|
195
|
-
if heredoc? last_arg
|
196
|
-
end_pos = heredoc_hack(last_arg).location.expression.end_pos
|
197
|
-
if buffer.source[ast.location.selector.end_pos] == '('
|
198
|
-
end_pos += 1 until buffer.source[end_pos] == ')'
|
199
|
-
end_pos += 1
|
200
|
-
end
|
201
|
-
|
202
|
-
# target is a heredoc, so we can't trust the expression
|
203
|
-
# but method has parens, so we can't trust the last arg
|
204
|
-
elsif heredoc?(target) && last_arg && buffer.source[ast.location.selector.end_pos] == '('
|
205
|
-
end_pos = last_arg.location.expression.end_pos
|
206
|
-
end_pos += 1 until buffer.source[end_pos] == ')'
|
207
|
-
end_pos += 1
|
208
|
-
|
209
|
-
elsif heredoc?(target) && last_arg
|
210
|
-
end_pos = last_arg.location.expression.end_pos
|
211
|
-
|
212
|
-
# neither the target, nor the last arg are heredocs, the range of the expression can be trusted
|
213
|
-
elsif last_arg
|
214
|
-
end_pos = ast.location.expression.end_pos
|
215
|
-
|
216
|
-
# in lambda{}.() the send has no selector, so use the expression
|
217
|
-
# I'm going to ignore the fact that you could define call on a heredoc and do <<HERE.(),
|
218
|
-
elsif !ast.location.selector
|
219
|
-
end_pos = ast.location.expression.end_pos
|
220
|
-
|
221
|
-
# there is no last arg, but there are parens, find the closing paren
|
222
|
-
# we can't trust the expression range because the *target* could be a heredoc
|
223
|
-
elsif buffer.source[ast.location.selector.end_pos] == '('
|
224
|
-
closing_paren_index = ast.location.selector.end_pos + 1
|
225
|
-
closing_paren_index += 1 until buffer.source[closing_paren_index] == ')'
|
226
|
-
end_pos = closing_paren_index + 1
|
227
|
-
|
228
|
-
# use the selector because we can't trust expression since target can be a heredoc
|
229
|
-
elsif heredoc? target
|
230
|
-
end_pos = ast.location.selector.end_pos
|
231
|
-
|
232
|
-
# use the expression because it could be something like !1, in which case the selector would return the rhs of the !
|
233
|
-
else
|
234
|
-
end_pos = ast.location.expression.end_pos
|
235
|
-
end
|
236
|
-
|
237
|
-
begin_pos = ast.location.expression.begin_pos
|
238
|
-
range = Parser::Source::Range.new(buffer, begin_pos, end_pos)
|
239
|
-
|
240
|
-
meta = nil
|
241
|
-
meta = :total_fucking_failure if message == :__TOTAL_FUCKING_FAILURE__
|
242
|
-
add_to_wrappings range, meta
|
182
|
+
_target, message, * = ast.children
|
183
|
+
meta = (:total_fucking_failure if message == :__TOTAL_FUCKING_FAILURE__)
|
184
|
+
add_to_wrappings ast, meta
|
243
185
|
add_children ast
|
244
186
|
when :begin
|
245
187
|
if ast.location.expression.source.start_with?("(") && # e.g. `(1)` we want `<(1)>`
|
246
|
-
|
188
|
+
!code.void_value?(ast) # e.g. `(return 1)` we want `(return <1>)`
|
247
189
|
add_to_wrappings ast
|
248
|
-
else # e.g. `A\nB` we want `<A>\n<B>`
|
249
|
-
last_child = ast.children.last
|
250
|
-
if heredoc? last_child
|
251
|
-
range = Parser::Source::Range.new buffer,
|
252
|
-
ast.location.expression.begin_pos,
|
253
|
-
heredoc_hack(last_child).location.expression.end_pos
|
254
|
-
add_to_wrappings range unless void_value? ast.children.last
|
255
|
-
end
|
256
190
|
end
|
257
191
|
add_children ast
|
258
192
|
when :str, :dstr, :xstr, :regexp
|
259
|
-
add_to_wrappings
|
193
|
+
add_to_wrappings ast
|
260
194
|
|
261
195
|
when :hash
|
262
196
|
# method arguments might not have braces around them
|
@@ -264,6 +198,12 @@ class SeeingIsBelieving
|
|
264
198
|
add_to_wrappings ast, meta if ast.location.begin
|
265
199
|
add_children ast
|
266
200
|
|
201
|
+
when :block_pass, :preexe, :postexe
|
202
|
+
add_children ast # strange, I'm not too sure about this :/
|
203
|
+
|
204
|
+
when :match_current_line # ie `if /abc/; ...; end`
|
205
|
+
add_to_wrappings ast, :match_current_line
|
206
|
+
|
267
207
|
else
|
268
208
|
add_to_wrappings ast
|
269
209
|
add_children ast
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'seeing_is_believing/wrap_expressions'
|
2
|
+
class SeeingIsBelieving
|
3
|
+
module WrapExpressionsWithInspect
|
4
|
+
def self.call(program)
|
5
|
+
WrapExpressions.call program,
|
6
|
+
before_each: -> line_number {
|
7
|
+
"("
|
8
|
+
},
|
9
|
+
after_each: -> line_number {
|
10
|
+
").tap { |v| $SiB.record_result :inspect, #{line_number}, v }"
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/seeing_is_believing.gemspec
CHANGED
@@ -19,7 +19,7 @@ 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", ">= 2.2", "< 3.0"
|
22
|
+
s.add_dependency "parser", ">= 2.2.0.2", "< 3.0"
|
23
23
|
|
24
24
|
s.add_development_dependency "haiti", ">= 0.1", "< 0.3"
|
25
25
|
s.add_development_dependency "rake", "~> 10.0"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# This is mostly tested in the cukes, but some are hard to hit
|
2
|
+
|
3
|
+
require 'seeing_is_believing/binary/align_chunk'
|
4
|
+
|
5
|
+
RSpec.describe '1-off alignment specs' do
|
6
|
+
def chunk(code)
|
7
|
+
code << "\n"
|
8
|
+
SeeingIsBelieving::Binary::AlignChunk.new code
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'AlignChunk' do
|
12
|
+
it 'considers entirely whitespace lines to be a chunk separator' do
|
13
|
+
empty_line = chunk "aaaaa\n\n1"
|
14
|
+
whitespace_line = chunk "aaaaa\n \t \n1"
|
15
|
+
expect(whitespace_line.line_length_for 1).to eq empty_line.line_length_for(1)
|
16
|
+
expect(whitespace_line.line_length_for 3).to eq empty_line.line_length_for(3)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'is not fooled by whitespace on the first/last line' do
|
20
|
+
expect(chunk(" \na\n ").line_length_for(2)).to eq 3
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'is not fooled by trailing whitespace in general' do
|
24
|
+
expect(chunk("a ").line_length_for(1)).to eq 3
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,11 +3,12 @@ require 'seeing_is_believing/binary/comment_lines'
|
|
3
3
|
|
4
4
|
RSpec.describe SeeingIsBelieving::Binary::CommentLines, 'passes in the each commentable line and the line number, and adds the returned text (whitespace+comment) to the end' do
|
5
5
|
def call(code, &block)
|
6
|
-
described_class.call
|
6
|
+
return described_class.call(code, &block) if code.end_with? "\n"
|
7
|
+
code << "\n"
|
8
|
+
described_class.call(code, &block).chomp
|
7
9
|
end
|
8
10
|
|
9
11
|
example 'just checking some edge cases' do
|
10
|
-
expect(call("") { ';' }).to eq ";"
|
11
12
|
expect(call("__END__\n1") { ';' }).to eq "__END__\n1"
|
12
13
|
expect(call("1\n__END__") { ';' }).to eq "1;\n__END__"
|
13
14
|
end
|
@@ -0,0 +1,657 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'seeing_is_believing/binary/config'
|
3
|
+
|
4
|
+
|
5
|
+
RSpec.describe SeeingIsBelieving::Binary::Config do
|
6
|
+
RSpec::Matchers.define :have_error do |error_assertion|
|
7
|
+
match do |config|
|
8
|
+
config.errors.find do |error|
|
9
|
+
case error_assertion
|
10
|
+
when Regexp
|
11
|
+
error_assertion =~ error.explanation
|
12
|
+
else
|
13
|
+
error.explanation.include? error_assertion
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
failure_message do |options|
|
19
|
+
"#{error_assertion.inspect} should have matched one of the errors: #{options[:errors].inspect}"
|
20
|
+
end
|
21
|
+
|
22
|
+
failure_message_when_negated do |options|
|
23
|
+
"#{error_assertion.inspect} should NOT have matched any of the errors: #{options[:errors].inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:matrix_file) { 'seeing_is_believing/the_matrix' }
|
28
|
+
let(:default_markers) { SeeingIsBelieving::Binary::Markers.new }
|
29
|
+
|
30
|
+
def parse(args)
|
31
|
+
described_class.new.parse_args(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_deprecated(flag, *args)
|
35
|
+
deprecated_args = parse([flag, *args]).deprecations
|
36
|
+
expect(deprecated_args.size).to eq 1
|
37
|
+
deprecated = deprecated_args.first
|
38
|
+
expect(deprecated.args).to eq [flag, *args]
|
39
|
+
expect(deprecated.explanation).to be_a_kind_of String
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_examples 'it requires a positive int argument' do |flags|
|
43
|
+
it 'expects an integer argument' do
|
44
|
+
flags.each do |flag|
|
45
|
+
expect(parse([flag, '1'])).to_not have_error /#{flag}/
|
46
|
+
expect(parse([flag, '0'])).to have_error /#{flag}/
|
47
|
+
expect(parse([flag, '-1'])).to have_error /#{flag}/
|
48
|
+
expect(parse([flag, '1.0'])).to have_error /#{flag}/
|
49
|
+
expect(parse([flag, 'a'])).to have_error /#{flag}/
|
50
|
+
expect(parse([flag, '' ])).to have_error /#{flag}/
|
51
|
+
expect(parse([flag ])).to have_error /#{flag}/
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
shared_examples 'it requires a non-negative float or int' do |flags|
|
57
|
+
it 'expects a non-negative float or int argument' do
|
58
|
+
flags.each do |flag|
|
59
|
+
expect(parse([flag, '1'])).to_not have_error /#{flag}/
|
60
|
+
expect(parse([flag, '0'])).to_not have_error /#{flag}/
|
61
|
+
expect(parse([flag, '-1'])).to have_error /#{flag}/
|
62
|
+
expect(parse([flag,'-1.0'])).to have_error /#{flag}/
|
63
|
+
expect(parse([flag, '1.0'])).to_not have_error /#{flag}/
|
64
|
+
expect(parse([flag, 'a'])).to have_error /#{flag}/
|
65
|
+
expect(parse([flag, '' ])).to have_error /#{flag}/
|
66
|
+
expect(parse([flag ])).to have_error /#{flag}/
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'parsing from args' do
|
72
|
+
it 'does not mutate the input array' do
|
73
|
+
ary = ['a']
|
74
|
+
parse(ary)
|
75
|
+
expect(ary).to eq ['a']
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'correctly parses multiple args' do
|
79
|
+
config = parse(%w[filename -h -r torequire])
|
80
|
+
expect(config.filename).to eq 'filename'
|
81
|
+
expect(config.lib_options.require_files).to include 'torequire'
|
82
|
+
expect(config.print_help?).to eq true
|
83
|
+
expect(config.errors).to be_empty
|
84
|
+
end
|
85
|
+
|
86
|
+
# This sill dance is b/c equality assertions are annoying and not relevant anywhere else
|
87
|
+
# Don't like having to go implement this stuff just for a few high-level tests.
|
88
|
+
def flat_options(config)
|
89
|
+
flat_keys = config.keys - [:lib_options, :annotator_options]
|
90
|
+
flat_keys.each_with_object({}) { |key, hash| hash[key] = config[key] }
|
91
|
+
end
|
92
|
+
def assert_same_flat_opts(args1, args2)
|
93
|
+
flatopts1 = flat_options parse args1
|
94
|
+
flatopts2 = flat_options parse args2
|
95
|
+
expect(flatopts1).to eq flatopts2
|
96
|
+
end
|
97
|
+
it 'can interpret conjoined short-flags' do
|
98
|
+
assert_same_flat_opts ['-hjg'], ['-h', '-j', '-g'] # help, json, debug
|
99
|
+
end
|
100
|
+
it 'can interpret conjoined short-flags where one of them is h+' do
|
101
|
+
assert_same_flat_opts ['-h+jg'], ['-h+', '-j', '-g']
|
102
|
+
assert_same_flat_opts ['-jh+g'], ['-j', '-h+', '-g']
|
103
|
+
assert_same_flat_opts ['-jgh+'], ['-j', '-g', '-h+']
|
104
|
+
end
|
105
|
+
|
106
|
+
specify 'unknown options set an error' do
|
107
|
+
expect(parse(['--xyz' ])).to have_error '--xyz is not an option'
|
108
|
+
expect(parse(['-y' ])).to have_error '-y is not an option'
|
109
|
+
expect(parse(['-y', 'b'])).to have_error '-y is not an option'
|
110
|
+
expect(parse(['-+h' ])).to have_error '-+ is not an option'
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'filename and lib_options.filename' do
|
114
|
+
specify 'default to nil' do
|
115
|
+
expect(parse([]).filename).to be_nil
|
116
|
+
expect(parse([]).lib_options.filename).to be_nil
|
117
|
+
end
|
118
|
+
|
119
|
+
specify 'both filename and lib_options.filename are set when a filename is seen' do
|
120
|
+
config = parse ['a']
|
121
|
+
expect(config.filename).to eq 'a'
|
122
|
+
expect(config.lib_options.filename).to eq 'a'
|
123
|
+
end
|
124
|
+
|
125
|
+
specify 'the filename is a nonflag / nonarg' do
|
126
|
+
# nonflag / nonarg
|
127
|
+
expect(parse(['-x']).filename).to eq nil
|
128
|
+
expect(parse(['-n', '3']).filename).to eq nil
|
129
|
+
|
130
|
+
# find it amidst flags/largs
|
131
|
+
expect(parse(['a']).filename).to eq 'a'
|
132
|
+
expect(parse(['-x', 'a']).filename).to eq 'a'
|
133
|
+
expect(parse(['a', '-x']).filename).to eq 'a'
|
134
|
+
expect(parse(['a', '-n', '3']).filename).to eq 'a'
|
135
|
+
expect(parse(['-n', '3', 'a', '-r', 'f']).filename).to eq 'a'
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'does not confuse filenames with unknown args' do
|
139
|
+
unknown_arg = '-y'
|
140
|
+
expect(parse([unknown_arg]).filename).to be_nil
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'sets an error if given multiple filenames' do
|
144
|
+
expect(parse([]).errors).to be_empty
|
145
|
+
expect(parse(['a']).errors).to be_empty
|
146
|
+
expect(parse(['a', 'b'])).to have_error /"a", "b"/
|
147
|
+
end
|
148
|
+
|
149
|
+
specify '-a and --as set lib_options.filename, but not filename' do
|
150
|
+
expect(parse(%w[-a abc]).filename).to eq nil
|
151
|
+
expect(parse(%w[--as abc]).filename).to eq nil
|
152
|
+
expect(parse(%w[-a abc]).lib_options.filename).to eq 'abc'
|
153
|
+
expect(parse(%w[--as abc]).lib_options.filename).to eq 'abc'
|
154
|
+
end
|
155
|
+
|
156
|
+
specify '-a and --as always win over a filename' do
|
157
|
+
config = parse(['fn', '-a', 'as'])
|
158
|
+
expect(config.filename).to eq 'fn'
|
159
|
+
expect(config.lib_options.filename).to eq 'as'
|
160
|
+
|
161
|
+
config = parse(['-a', 'as', 'fn'])
|
162
|
+
expect(config.filename).to eq 'fn'
|
163
|
+
expect(config.lib_options.filename).to eq 'as'
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'sets an error if -a/--as are given without the filename to execute as' do
|
167
|
+
expect(parse(%w[-a f])).to_not have_error /-a/
|
168
|
+
expect(parse(%w[-as f])).to_not have_error /--as/
|
169
|
+
expect(parse(%w[-a ])).to have_error /-a/
|
170
|
+
expect(parse(%w[--as ])).to have_error /--as/
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
describe 'annotator_options.max_result_length' do
|
176
|
+
it 'defaults to infinity' do
|
177
|
+
expect(parse([]).annotator_options.max_result_length).to eq Float::INFINITY
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'is set with -D and --result-length' do
|
181
|
+
expect(parse(['-D', '10']).annotator_options.max_result_length).to eq 10
|
182
|
+
expect(parse(['--result-length', '10']).annotator_options.max_result_length).to eq 10
|
183
|
+
end
|
184
|
+
|
185
|
+
it_behaves_like 'it requires a positive int argument', ['-D', '--result-length']
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'annotator_options.max_line_length' do
|
189
|
+
it 'defaults to infinity' do
|
190
|
+
expect(parse([]).annotator_options.max_line_length).to eq Float::INFINITY
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'is set with -d and --line-length' do
|
194
|
+
expect(parse(['-d', '10']).annotator_options.max_line_length).to eq 10
|
195
|
+
expect(parse(['--line-length', '10']).annotator_options.max_line_length).to eq 10
|
196
|
+
end
|
197
|
+
|
198
|
+
it_behaves_like 'it requires a positive int argument', ['-d', '--line-length']
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'lib_options.require_files' do
|
202
|
+
it 'defaults to the matrix file array' do
|
203
|
+
expect(parse([]).lib_options.require_files).to eq [matrix_file]
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'appends pp for xmpfilter style' do
|
207
|
+
expect(parse(['-x']).lib_options.require_files).to eq [matrix_file, 'pp']
|
208
|
+
end
|
209
|
+
|
210
|
+
specify '-r and --require set an error if not provided with a filename' do
|
211
|
+
expect(parse(['--require', 'f'])).to_not have_error /-r/
|
212
|
+
expect(parse(['-r'])).to have_error /-r\b/
|
213
|
+
expect(parse(['--require'])).to have_error /--require\b/
|
214
|
+
end
|
215
|
+
|
216
|
+
specify '-r and --require add the filename into the result array' do
|
217
|
+
expect(parse(%w[-r f1 --require f2]).lib_options.require_files).to eq [matrix_file, 'f1', 'f2']
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe 'print_help? and help_screen' do
|
222
|
+
let(:help_screen) { SeeingIsBelieving::Binary.help_screen default_markers }
|
223
|
+
let(:help_screen_extended) { SeeingIsBelieving::Binary.help_screen_extended default_markers }
|
224
|
+
|
225
|
+
specify 'print_help? defaults to false' do
|
226
|
+
expect(parse([]).print_help?).to eq false
|
227
|
+
end
|
228
|
+
|
229
|
+
specify 'help_screen defaults to the short help screen' do
|
230
|
+
expect(parse([]).help_screen).to eq help_screen
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'print_help? is set to true with -h, --help, -h+, and --help+' do
|
234
|
+
expect(parse(['-h']).print_help?).to eq true
|
235
|
+
expect(parse(['-h+']).print_help?).to eq true
|
236
|
+
expect(parse(['--help']).print_help?).to eq true
|
237
|
+
expect(parse(['--help+']).print_help?).to eq true
|
238
|
+
end
|
239
|
+
|
240
|
+
specify '-h and --help set help_screen to the short help screen' do
|
241
|
+
expect(parse(['-h']).help_screen).to eq help_screen
|
242
|
+
expect(parse(['--help']).help_screen).to eq help_screen
|
243
|
+
end
|
244
|
+
|
245
|
+
specify '-h+ and --help+ set help_screen to the extended help screen' do
|
246
|
+
expect(parse(['-h+']).help_screen).to eq help_screen_extended
|
247
|
+
expect(parse(['--help+']).help_screen).to eq help_screen_extended
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
describe 'body' do
|
253
|
+
it 'defaults to nil' do
|
254
|
+
expect(parse([]).body).to eq nil
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'is set by an arg to -e and --program' do
|
258
|
+
expect(parse(['-e', '1']).body).to eq '1'
|
259
|
+
expect(parse(['--program', '1']).body).to eq '1'
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'sets an error if -e and --program are not given an arg' do
|
263
|
+
expect(parse([])).to_not have_error /-e/
|
264
|
+
expect(parse([])).to_not have_error /--program/
|
265
|
+
expect(parse(['-e', 'body'])).to_not have_error /-e/
|
266
|
+
expect(parse(['-e' ])).to have_error /-e/
|
267
|
+
expect(parse(['--program', 'body'])).to_not have_error /--program/
|
268
|
+
expect(parse(['--program' ])).to have_error /--program/
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
describe'lib_options.load_path_dirs' do
|
273
|
+
let(:lib_path) { File.expand_path '../../../lib', __FILE__ }
|
274
|
+
|
275
|
+
it 'defaults to sib\'s lib path' do
|
276
|
+
expect(parse([]).lib_options.load_path_dirs).to eq [lib_path]
|
277
|
+
end
|
278
|
+
|
279
|
+
specify '-I and --load-path add their arguments to it' do
|
280
|
+
expect(parse(%w[-I f1 --load-path f2]).lib_options.load_path_dirs).to eq [lib_path, 'f1', 'f2']
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'sets an error if not provided with a dir' do
|
284
|
+
expect(parse(['--load-path', 'f'])).to_not have_error /--load-path/
|
285
|
+
expect(parse(['-I'])).to have_error /-I\b/
|
286
|
+
expect(parse(['--load-path'])).to have_error /--load-path\b/
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe 'lib_options.encoding' do
|
291
|
+
it 'defaults to nil' do
|
292
|
+
expect(parse([]).lib_options.encoding).to be_nil
|
293
|
+
end
|
294
|
+
|
295
|
+
specify '-K and --encoding sets the encoding to the next argument' do
|
296
|
+
expect(parse(%w[-K u]).lib_options.encoding).to eq 'u'
|
297
|
+
expect(parse(%w[--encoding u]).lib_options.encoding).to eq 'u'
|
298
|
+
end
|
299
|
+
|
300
|
+
specify 'with -K, the argument can be placed immediately after it (e.g. -Ku) because Ruby allows this' do
|
301
|
+
expect(parse(['-Ku']).lib_options.encoding).to eq 'u'
|
302
|
+
expect(parse(['-Ku'])).to_not have_error /-K/
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'sets an error if not provided with an encoding' do
|
306
|
+
expect(parse(['-Ku'])).to_not have_error /-K/
|
307
|
+
expect(parse(['-K u'])).to_not have_error /-K/
|
308
|
+
expect(parse(['--encoding', 'u'])).to_not have_error /--encoding/
|
309
|
+
expect(parse(['-K'])).to have_error /-K/
|
310
|
+
expect(parse(['--encoding'])).to have_error /--encoding/
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe '.print_cleaned?' do
|
315
|
+
it 'defaults to false' do
|
316
|
+
expect(parse([]).print_cleaned?).to eq false
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'can be set with -c and --clean' do
|
320
|
+
expect(parse(%w[-c]).print_cleaned?).to eq true
|
321
|
+
expect(parse(%w[--clean]).print_cleaned?).to eq true
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe 'print_version?' do
|
326
|
+
it 'defaults to false' do
|
327
|
+
expect(parse([]).print_version?).to eq false
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'can be set with -v and --version' do
|
331
|
+
expect(parse(%w[-v]).print_version?).to eq true
|
332
|
+
expect(parse(%w[--version]).print_version?).to eq true
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
describe 'timeout and lib_options.timeout_seconds' do
|
337
|
+
it 'defaults to 0 (never timeout)' do
|
338
|
+
expect(parse([]).timeout_seconds).to eq 0
|
339
|
+
expect(parse([]).lib_options.timeout_seconds).to eq 0
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'can be set with -t and --timeout-seconds' do
|
343
|
+
expect(parse(['-t', '1.1']).timeout_seconds).to eq 1.1
|
344
|
+
expect(parse(['-t', '1.1']).lib_options.timeout_seconds).to eq 1.1
|
345
|
+
expect(parse(['--timeout-seconds', '1.2']).lib_options.timeout_seconds).to eq 1.2
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'can be set with the deprecated flag --timeout' do
|
349
|
+
expect(parse(['--timeout', '1.3']).lib_options.timeout_seconds).to eq 1.3
|
350
|
+
assert_deprecated '--timeout', 1.4
|
351
|
+
end
|
352
|
+
|
353
|
+
it_behaves_like 'it requires a non-negative float or int', ['-t', '--timeout-seconds', '--timeout']
|
354
|
+
end
|
355
|
+
|
356
|
+
describe 'annotator_options.alignment_strategy' do
|
357
|
+
let(:align_chunk) { SeeingIsBelieving::Binary::AlignChunk }
|
358
|
+
let(:align_file) { SeeingIsBelieving::Binary::AlignFile }
|
359
|
+
let(:align_line) { SeeingIsBelieving::Binary::AlignLine }
|
360
|
+
|
361
|
+
it 'defaults to AlignChunk' do
|
362
|
+
expect(parse([]).annotator_options.alignment_strategy)
|
363
|
+
.to eq align_chunk
|
364
|
+
end
|
365
|
+
|
366
|
+
specify '-s and --alignment-strategy sets the alignment strategy' do
|
367
|
+
expect(parse(['-s', 'file']).annotator_options.alignment_strategy)
|
368
|
+
.to eq align_file
|
369
|
+
|
370
|
+
expect(parse(['--alignment-strategy', 'file']).annotator_options.alignment_strategy)
|
371
|
+
.to eq align_file
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'accepts values: file, line, chunk' do
|
375
|
+
expect(parse(['-s', 'file']).annotator_options.alignment_strategy).to eq align_file
|
376
|
+
expect(parse(['-s', 'line']).annotator_options.alignment_strategy).to eq align_line
|
377
|
+
expect(parse(['-s', 'chunk']).annotator_options.alignment_strategy).to eq align_chunk
|
378
|
+
end
|
379
|
+
|
380
|
+
it 'sets an error if not provided with a strategy' do
|
381
|
+
expect(parse(['-s'])).to have_error /-s/
|
382
|
+
expect(parse(['-s', 'file'])).to_not have_error /-s/
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'sets an error if provided with an unknown alignment strategy' do
|
386
|
+
expect(parse(['-s', 'file'])).to_not have_error '-s'
|
387
|
+
expect(parse(['-s', 'unknown'])).to have_error '-s', 'expected one of'
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe 'inherit_exitstatus?' do
|
392
|
+
it 'defaults to false' do
|
393
|
+
expect(parse([]).inherit_exitstatus?).to eq false
|
394
|
+
end
|
395
|
+
|
396
|
+
it 'can be set with --inherit-exitstatus, -i' do
|
397
|
+
expect(parse(['--inherit-exitstatus']).inherit_exitstatus?).to be true
|
398
|
+
expect(parse(['-i']).inherit_exitstatus?).to be true
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'can be set with the deprecated --inherit-exit-status' do
|
402
|
+
expect(parse(['--inherit-exit-status']).inherit_exitstatus?).to be true
|
403
|
+
assert_deprecated '--inherit-exit-status'
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
describe 'annotator and lib_options.rewrite_code' do
|
408
|
+
specify 'annotator defaults to AnnotateEveryLine' do
|
409
|
+
expect(parse([]).annotator).to be SeeingIsBelieving::Binary::AnnotateEveryLine
|
410
|
+
end
|
411
|
+
|
412
|
+
specify 'annotator can be set to AnnotateMarkedLines with --xmpfilter-style or -x' do
|
413
|
+
expect(parse(['--xmpfilter-style']).annotator).to eq SeeingIsBelieving::Binary::AnnotateMarkedLines
|
414
|
+
expect(parse(['-x']).annotator).to eq SeeingIsBelieving::Binary::AnnotateMarkedLines
|
415
|
+
end
|
416
|
+
|
417
|
+
specify 'lib_options.rewrite_code is set to the xmpfilter rewriter on -x and --xmpfilter-style' do
|
418
|
+
# not a great test, but the cukes hit its actual behaviour
|
419
|
+
expect(parse([]).lib_options.rewrite_code.call("1 # =>\n")).to_not include "pp"
|
420
|
+
expect(parse(['-x']).lib_options.rewrite_code.call("1\n# =>\n")).to include "pp"
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe 'remove_value_prefixes?', t:true do
|
425
|
+
it 'defaults to true' do
|
426
|
+
expect(parse([]).remove_value_prefixes?).to eq true
|
427
|
+
end
|
428
|
+
it 'is false when xmpfilter style is specified' do
|
429
|
+
expect(parse(['-x']).remove_value_prefixes?).to eq false
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
describe 'debug?' do
|
434
|
+
specify 'debug? defaults to a false' do
|
435
|
+
expect(parse([])[:debug]).to eq false
|
436
|
+
end
|
437
|
+
|
438
|
+
specify '-g and --debug set debug? to true' do
|
439
|
+
expect(parse(['-g']).debug?).to eq true
|
440
|
+
expect(parse(['--debug']).debug?).to eq true
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
describe '--shebang' do
|
445
|
+
it 'is added to the list of deprecated flags' do
|
446
|
+
assert_deprecated '--shebang', 'not_ruby'
|
447
|
+
end
|
448
|
+
|
449
|
+
it 'sets an error if not given a next arg to execute' do
|
450
|
+
expect(parse([])).to_not have_error /--shebang/
|
451
|
+
expect(parse(['--shebang', 'arg'])).to_not have_error /--shebang/
|
452
|
+
expect(parse(['--shebang'])).to have_error /--shebang/
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
describe 'lib_options.max_line_captures' do
|
457
|
+
it 'defaults to infinity' do
|
458
|
+
expect(parse([]).lib_options.max_line_captures).to eq Float::INFINITY
|
459
|
+
end
|
460
|
+
|
461
|
+
it 'can be set with --max-line-captures or -n' do
|
462
|
+
expect(parse(['-n', '10']).lib_options.max_line_captures).to eq 10
|
463
|
+
expect(parse(['--max-line-captures', '10']).lib_options.max_line_captures).to eq 10
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'can be set with the deprecated flag --number-of-captures' do
|
467
|
+
expect(parse(['--number-of-captures', '12']).lib_options.max_line_captures).to eq 12
|
468
|
+
assert_deprecated '--number-of-captures', '12'
|
469
|
+
assert_deprecated '--number-of-captures'
|
470
|
+
end
|
471
|
+
|
472
|
+
it_behaves_like 'it requires a positive int argument', ['-n', '--max-line-captures', '--number-of-captures']
|
473
|
+
end
|
474
|
+
|
475
|
+
describe 'result_as_json?' do
|
476
|
+
it 'defaults to false' do
|
477
|
+
expect(parse([]).result_as_json?).to eq false
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'can be enabled with --json or -j' do
|
481
|
+
expect(parse(['--json']).result_as_json?).to eq true
|
482
|
+
expect(parse(['-j']).result_as_json?).to eq true
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'sets an error if specified with xmpfilter' do
|
486
|
+
expect(parse(['--json'])).to_not have_error /json/
|
487
|
+
expect(parse(['--json', '-x'])).to have_error /json/
|
488
|
+
expect(parse(['--json', '--xmpfilter-style'])).to have_error /json/
|
489
|
+
expect(parse(['-x', '--json'])).to have_error /json/
|
490
|
+
expect(parse(['--xmpfilter-style', '--json'])).to have_error /json/
|
491
|
+
expect(parse(['-j', '-x'])).to have_error /json/
|
492
|
+
expect(parse(['-j', '-x'])).to have_error /xmpfilter/
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
describe 'markers' do
|
497
|
+
it 'defaults to a hash with :value, :exception, :stdout, and :stderr' do
|
498
|
+
expect(default_markers.keys).to eq [:value, :exception, :stdout, :stderr]
|
499
|
+
end
|
500
|
+
|
501
|
+
specify 'each default marker regex can re-find the the marker' do
|
502
|
+
default_markers.each do |name, marker|
|
503
|
+
comment = "#{marker.prefix}abc"
|
504
|
+
extracted = comment[marker.regex]
|
505
|
+
expect(extracted).to eq(marker.prefix)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
it('defaults :value to "# => "') { expect(default_markers.value .prefix).to eq "# => " }
|
510
|
+
it('defaults :exception to "# ~> "') { expect(default_markers.exception.prefix).to eq "# ~> " }
|
511
|
+
it('defaults :stdout to "# >> "') { expect(default_markers.stdout .prefix).to eq "# >> " }
|
512
|
+
it('defaults :stderr to "# !> "') { expect(default_markers.stderr .prefix).to eq "# !> " }
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
describe 'print_event_stream?' do
|
517
|
+
it 'print_event_stream? is false by default' do
|
518
|
+
expect(parse([]).print_event_stream?).to eq false
|
519
|
+
end
|
520
|
+
it 'print_event_stream? can be turned on with --stream' do
|
521
|
+
expect(parse(['--stream']).print_event_stream?).to eq true
|
522
|
+
end
|
523
|
+
it 'adds an error if --stream is used with --json' do
|
524
|
+
expect(parse(['--stream'])).to_not have_error '--stream'
|
525
|
+
expect(parse(['--stream', '--json'])).to have_error '--stream'
|
526
|
+
expect(parse(['--json', '--stream'])).to have_error '--stream'
|
527
|
+
end
|
528
|
+
it 'adds an error if --stream is used with -x or --xmpfilter-style' do
|
529
|
+
expect(parse(['--stream'])).to_not have_error '--stream'
|
530
|
+
expect(parse(['--stream', '-x'])).to have_error '--stream'
|
531
|
+
expect(parse(['-x', '--stream'])).to have_error '--stream'
|
532
|
+
expect(parse(['--xmpfilter-style', '--stream'])).to have_error '--stream'
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
|
537
|
+
describe '.finalize' do
|
538
|
+
let(:stdin_data) { 'stdin data' }
|
539
|
+
let(:stdin) { object_double $stdin, read: stdin_data }
|
540
|
+
let(:stdout) { object_double $stdout }
|
541
|
+
let(:stderr) { object_double $stderr }
|
542
|
+
|
543
|
+
let(:file_class) { class_double File }
|
544
|
+
let(:nonexisting_filename) { 'badfilename' }
|
545
|
+
let(:existing_filename) { 'goodfilename' }
|
546
|
+
let(:file_body) { 'good file body' }
|
547
|
+
|
548
|
+
before do
|
549
|
+
allow(file_class).to receive(:exist?).with(existing_filename).and_return(true)
|
550
|
+
allow(file_class).to receive(:exist?).with(nonexisting_filename).and_return(false)
|
551
|
+
allow(file_class).to receive(:read).with(existing_filename).and_return(file_body)
|
552
|
+
end
|
553
|
+
|
554
|
+
def call(attrs={})
|
555
|
+
described_class.new(attrs).finalize(stdin, stdout, stderr, file_class)
|
556
|
+
end
|
557
|
+
|
558
|
+
describe 'additional errors' do
|
559
|
+
it 'sets an error if given a filename and a program body -- cannot have two body sources' do
|
560
|
+
allow(file_class).to receive(:exist?).with('f')
|
561
|
+
matcher = /program body and a filename/
|
562
|
+
expect(call filename: 'f', body: 'b').to have_error matcher
|
563
|
+
expect(call filename: 'f', body: 'b').to have_error matcher
|
564
|
+
expect(call filename: nil, body: 'b').to_not have_error matcher
|
565
|
+
expect(call filename: 'f', body: nil).to_not have_error matcher
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'sets an error if the provided filename DNE' do
|
569
|
+
expect(call filename: existing_filename).to_not have_error /filename/
|
570
|
+
expect(call filename: nonexisting_filename).to have_error /filename/
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
describe 'setting the body' do
|
575
|
+
it 'does not override the if already set e.g. with -e' do
|
576
|
+
expect(call(body: 'b', filename: nil).body).to eq 'b'
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'is the file body if the filename is provded and exists' do
|
580
|
+
expect(call(body: nil, filename: existing_filename).body)
|
581
|
+
.to eq file_body
|
582
|
+
end
|
583
|
+
|
584
|
+
it 'is an empty string if the filename is provided but DNE' do
|
585
|
+
expect(call(body: nil, filename: nonexisting_filename).body)
|
586
|
+
.to eq nil
|
587
|
+
end
|
588
|
+
|
589
|
+
it 'reads the body from stdin if not given a filename or body' do
|
590
|
+
expect(call(body: nil, filename: nil).body).to eq stdin_data
|
591
|
+
end
|
592
|
+
|
593
|
+
it 'is set to an empty string when we aren\'t evaluating (e.g. when printing version info)' do
|
594
|
+
expect(call( ).body).to be_a_kind_of String
|
595
|
+
expect(call(print_version: true).body).to eq ''
|
596
|
+
expect(call(print_help: true).body).to eq ''
|
597
|
+
expect(call(errors: ['e']).body).to eq ''
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
describe 'lib_options.stdin' do
|
602
|
+
let(:default) { SeeingIsBelieving::Options.new.stdin }
|
603
|
+
|
604
|
+
it 'is the default when we aren\'t evaluating' do
|
605
|
+
[ {errors: ['e']},
|
606
|
+
{filename: existing_filename, body: 'b'},
|
607
|
+
{filename: nonexisting_filename},
|
608
|
+
{print_version: true},
|
609
|
+
{print_help: true},
|
610
|
+
].each do |overrides|
|
611
|
+
expect(call(overrides).lib_options.stdin).to eq default
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'is the default when the program was taken off stdin' do
|
616
|
+
expect(call.lib_options.stdin).to eq default
|
617
|
+
expect(call(body: 'b').lib_options.stdin).to_not eq default
|
618
|
+
end
|
619
|
+
|
620
|
+
it 'is the stdin stream when the program body was provided' do
|
621
|
+
expect(call(body: 'b').lib_options.stdin).to eq stdin
|
622
|
+
end
|
623
|
+
|
624
|
+
it 'is the stdin stream when the program was pulled from a file' do
|
625
|
+
expect(call(filename: existing_filename).lib_options.stdin).to eq stdin
|
626
|
+
expect(call(filename: nonexisting_filename).lib_options.stdin).to eq default
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
describe 'lib_options.event_handler' do
|
631
|
+
it 'is an UpdateResult handler when print_event_stream? is false' do
|
632
|
+
expect(call(print_event_stream: false).lib_options.event_handler)
|
633
|
+
.to be_an_instance_of SeeingIsBelieving::EventStream::Handlers::UpdateResult
|
634
|
+
end
|
635
|
+
it 'is an StreamJsonEvents handler to stdout when print_event_stream? is true' do
|
636
|
+
handler = call(print_event_stream: true).lib_options.event_handler
|
637
|
+
expect(handler).to be_an_instance_of SeeingIsBelieving::EventStream::Handlers::StreamJsonEvents
|
638
|
+
expect(handler.stream).to eq stdout
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
describe 'debugger, lib_options.debugger' do
|
643
|
+
specify 'default to a null debugger' do
|
644
|
+
handler = call
|
645
|
+
expect(handler.debugger).to_not be_enabled
|
646
|
+
expect(handler.lib_options.debugger).to_not be_enabled
|
647
|
+
end
|
648
|
+
|
649
|
+
specify 'are set to debug to stderr when debug? is true' do
|
650
|
+
handler = call debug: true
|
651
|
+
expect(handler.debugger).to be_enabled
|
652
|
+
expect(handler.debugger.stream).to eq stderr
|
653
|
+
expect(handler.lib_options.debugger).to equal handler.debugger
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|