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