optimist 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -1
- data/.github/workflows/ci.yaml +3 -1
- data/CHANGELOG.md +222 -2
- data/examples/a_basic_example.rb +10 -0
- data/examples/alt_names.rb +20 -0
- data/examples/banners1.rb +11 -0
- data/examples/banners2.rb +12 -0
- data/examples/banners3.rb +14 -0
- data/examples/constraints.rb +28 -0
- data/examples/didyoumean.rb +26 -0
- data/examples/medium_example.rb +15 -0
- data/examples/partialmatch.rb +18 -0
- data/examples/permitted.rb +29 -0
- data/examples/types_custom.rb +43 -0
- data/lib/optimist.rb +347 -93
- data/optimist.gemspec +1 -1
- data/renovate.json +6 -0
- data/test/optimist/alt_names_test.rb +168 -0
- data/test/optimist/command_line_error_test.rb +1 -1
- data/test/optimist/help_needed_test.rb +1 -1
- data/test/optimist/parser_constraint_test.rb +141 -0
- data/test/optimist/parser_educate_test.rb +22 -1
- data/test/optimist/parser_opt_test.rb +1 -1
- data/test/optimist/parser_parse_test.rb +3 -3
- data/test/optimist/parser_permitted_test.rb +121 -0
- data/test/optimist/parser_test.rb +277 -176
- data/test/optimist/version_needed_test.rb +1 -1
- data/test/optimist_test.rb +5 -3
- data/test/support/assert_helpers.rb +6 -0
- metadata +22 -5
- data/History.txt +0 -175
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
|
4
4
|
module Optimist
|
5
5
|
|
6
|
-
class ParserTest < ::
|
6
|
+
class ParserTest < ::Minitest::Test
|
7
7
|
def setup
|
8
8
|
@p = Parser.new
|
9
9
|
end
|
@@ -35,8 +35,6 @@ class ParserTest < ::MiniTest::Test
|
|
35
35
|
assert_equal "synopsis string", parser.synopsis
|
36
36
|
end
|
37
37
|
|
38
|
-
# def test_depends
|
39
|
-
# def test_conflicts
|
40
38
|
# def test_stop_on
|
41
39
|
# def test_stop_on_unknown
|
42
40
|
|
@@ -45,10 +43,57 @@ class ParserTest < ::MiniTest::Test
|
|
45
43
|
|
46
44
|
|
47
45
|
def test_unknown_arguments
|
48
|
-
|
46
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--arg'/) { @p.parse(%w(--arg)) }
|
49
47
|
@p.opt "arg"
|
50
48
|
@p.parse(%w(--arg))
|
51
|
-
|
49
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--arg2'/) { @p.parse(%w(--arg2)) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_unknown_arguments_with_suggestions
|
53
|
+
unless (Module::const_defined?("DidYouMean") &&
|
54
|
+
Module::const_defined?("DidYouMean::JaroWinkler") &&
|
55
|
+
Module::const_defined?("DidYouMean::Levenshtein"))
|
56
|
+
# if we cannot
|
57
|
+
skip("Skipping because DidYouMean was not found")
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
sugp = Parser.new(:suggestions => true)
|
61
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--bone)) }
|
62
|
+
assert_match(/unknown argument '--bone'$/, err.message)
|
63
|
+
|
64
|
+
sugp.opt "cone"
|
65
|
+
sugp.parse(%w(--cone))
|
66
|
+
|
67
|
+
# single letter mismatch
|
68
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--bone)) }
|
69
|
+
assert_match(/unknown argument '--bone'. Did you mean: \[--cone\] \?$/, err.message)
|
70
|
+
|
71
|
+
# transposition
|
72
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--ocne)) }
|
73
|
+
assert_match(/unknown argument '--ocne'. Did you mean: \[--cone\] \?$/, err.message)
|
74
|
+
|
75
|
+
# extra letter at end
|
76
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--cones)) }
|
77
|
+
assert_match(/unknown argument '--cones'. Did you mean: \[--cone\] \?$/, err.message)
|
78
|
+
|
79
|
+
# too big of a mismatch to suggest (extra letters in front)
|
80
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--snowcone)) }
|
81
|
+
assert_match(/unknown argument '--snowcone'$/, err.message)
|
82
|
+
|
83
|
+
# too big of a mismatch to suggest (nothing close)
|
84
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--clown-nose)) }
|
85
|
+
assert_match(/unknown argument '--clown-nose'$/, err.message)
|
86
|
+
|
87
|
+
sugp.opt "zippy"
|
88
|
+
sugp.opt "zapzy"
|
89
|
+
# single letter mismatch, matches two
|
90
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--zipzy)) }
|
91
|
+
assert_match(/unknown argument '--zipzy'. Did you mean: \[--zippy, --zapzy\] \?$/, err.message)
|
92
|
+
|
93
|
+
sugp.opt "big_bug"
|
94
|
+
# suggest common case of dash versus underscore in argnames
|
95
|
+
err = assert_raises(CommandlineError) { sugp.parse(%w(--big_bug)) }
|
96
|
+
assert_match(/unknown argument '--big_bug'. Did you mean: \[--big-bug\] \?$/, err.message)
|
52
97
|
end
|
53
98
|
|
54
99
|
def test_syntax_check
|
@@ -56,8 +101,8 @@ class ParserTest < ::MiniTest::Test
|
|
56
101
|
|
57
102
|
@p.parse(%w(--arg))
|
58
103
|
@p.parse(%w(arg))
|
59
|
-
|
60
|
-
|
104
|
+
assert_raises_errmatch(CommandlineError, /invalid argument syntax: '---arg'/) { @p.parse(%w(---arg)) }
|
105
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-r'/) { @p.parse(%w(-arg)) }
|
61
106
|
end
|
62
107
|
|
63
108
|
def test_required_flags_are_required
|
@@ -67,8 +112,9 @@ class ParserTest < ::MiniTest::Test
|
|
67
112
|
|
68
113
|
@p.parse(%w(--arg))
|
69
114
|
@p.parse(%w(--arg --arg2))
|
70
|
-
|
71
|
-
|
115
|
+
err_regex = %r/option --arg must be specified/
|
116
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--arg2)) }
|
117
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--arg2 --arg3)) }
|
72
118
|
end
|
73
119
|
|
74
120
|
## flags that take an argument error unless given one
|
@@ -77,8 +123,9 @@ class ParserTest < ::MiniTest::Test
|
|
77
123
|
@p.opt "goodarg2", "desc", :type => String
|
78
124
|
|
79
125
|
@p.parse(%w(--goodarg goat))
|
80
|
-
|
81
|
-
|
126
|
+
err_regex = %r/option '--goodarg' needs a parameter/
|
127
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg --goodarg2 goat)) }
|
128
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg)) }
|
82
129
|
end
|
83
130
|
|
84
131
|
## flags that don't take arguments ignore them
|
@@ -95,19 +142,24 @@ class ParserTest < ::MiniTest::Test
|
|
95
142
|
## flags that require args of a specific type refuse args of other
|
96
143
|
## types
|
97
144
|
def test_typed_args_refuse_args_of_other_types
|
98
|
-
@p.opt "goodarg", "desc", :type => :int
|
99
|
-
|
145
|
+
@p.opt "goodarg", "desc", :type => :int
|
146
|
+
err_regex = %r/Unsupported argument type 'asdf', registry lookup 'asdf'/
|
147
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :type => :asdf }
|
100
148
|
|
101
149
|
@p.parse(%w(--goodarg 3))
|
102
|
-
|
103
|
-
|
150
|
+
err_regex = %r/option 'goodarg' needs an integer/
|
151
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg 4.2)) }
|
152
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--goodarg hello)) }
|
104
153
|
end
|
105
154
|
|
106
155
|
## type is correctly derived from :default
|
107
156
|
def test_type_correctly_derived_from_default
|
108
|
-
|
109
|
-
|
110
|
-
|
157
|
+
err_regex = %r/multiple argument type cannot be deduced from an empty array/
|
158
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :default => [] }
|
159
|
+
err_regex = %r/Unsupported argument type 'hashs', registry lookup 'hashs'/
|
160
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :default => [{1 => 2}] }
|
161
|
+
err_regex = %r/Unsupported argument type 'hash', registry lookup 'hash'/
|
162
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg4", "desc", :default => Hash.new }
|
111
163
|
|
112
164
|
# single arg: int
|
113
165
|
@p.opt "argsi", "desc", :default => 0
|
@@ -119,9 +171,9 @@ class ParserTest < ::MiniTest::Test
|
|
119
171
|
assert_equal 4, opts["argsi"]
|
120
172
|
opts = @p.parse(%w(--argsi=-4))
|
121
173
|
assert_equal( -4, opts["argsi"])
|
122
|
-
|
123
|
-
|
124
|
-
|
174
|
+
err_regex = /option 'argsi' needs an integer/
|
175
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsi 4.2)) }
|
176
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsi hello)) }
|
125
177
|
|
126
178
|
# single arg: float
|
127
179
|
@p.opt "argsf", "desc", :default => 3.14
|
@@ -133,7 +185,8 @@ class ParserTest < ::MiniTest::Test
|
|
133
185
|
assert_equal 2, opts["argsf"]
|
134
186
|
opts = @p.parse(%w(--argsf 1.0e-2))
|
135
187
|
assert_equal 1.0e-2, opts["argsf"]
|
136
|
-
|
188
|
+
err_regex = /option 'argsf' needs a floating-point number/
|
189
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsf hello)) }
|
137
190
|
|
138
191
|
# single arg: date
|
139
192
|
date = Date.today
|
@@ -142,7 +195,8 @@ class ParserTest < ::MiniTest::Test
|
|
142
195
|
assert_equal Date.today, opts["argsd"]
|
143
196
|
opts = @p.parse(['--argsd', 'Jan 4, 2007'])
|
144
197
|
assert_equal Date.civil(2007, 1, 4), opts["argsd"]
|
145
|
-
|
198
|
+
err_regex = /option 'argsd' needs a date/
|
199
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argsd hello)) }
|
146
200
|
|
147
201
|
# single arg: string
|
148
202
|
@p.opt "argss", "desc", :default => "foobar"
|
@@ -159,8 +213,9 @@ class ParserTest < ::MiniTest::Test
|
|
159
213
|
assert_equal [3, 5], opts["argmi"]
|
160
214
|
opts = @p.parse(%w(--argmi 4))
|
161
215
|
assert_equal [4], opts["argmi"]
|
162
|
-
|
163
|
-
|
216
|
+
err_regex = /option 'argmi' needs an integer/
|
217
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmi 4.2)) }
|
218
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmi hello)) }
|
164
219
|
|
165
220
|
# multi args: floats
|
166
221
|
@p.opt "argmf", "desc", :default => [3.34, 5.21]
|
@@ -170,7 +225,8 @@ class ParserTest < ::MiniTest::Test
|
|
170
225
|
assert_equal [2], opts["argmf"]
|
171
226
|
opts = @p.parse(%w(--argmf 4.0))
|
172
227
|
assert_equal [4.0], opts["argmf"]
|
173
|
-
|
228
|
+
err_regex = /option 'argmf' needs a floating-point number/
|
229
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmf hello)) }
|
174
230
|
|
175
231
|
# multi args: dates
|
176
232
|
dates = [Date.today, Date.civil(2007, 1, 4)]
|
@@ -179,7 +235,8 @@ class ParserTest < ::MiniTest::Test
|
|
179
235
|
assert_equal dates, opts["argmd"]
|
180
236
|
opts = @p.parse(['--argmd', 'Jan 4, 2007'])
|
181
237
|
assert_equal [Date.civil(2007, 1, 4)], opts["argmd"]
|
182
|
-
|
238
|
+
err_regex = /option 'argmd' needs a date/
|
239
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse(%w(--argmd hello)) }
|
183
240
|
|
184
241
|
# multi args: strings
|
185
242
|
@p.opt "argmst", "desc", :default => %w(hello world)
|
@@ -193,10 +250,12 @@ class ParserTest < ::MiniTest::Test
|
|
193
250
|
|
194
251
|
## :type and :default must match if both are specified
|
195
252
|
def test_type_and_default_must_match
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
253
|
+
# Different versions of ruby raise different error messages.
|
254
|
+
err_regex = %r/(type specification and default type don't match|Unsupported argument type)/
|
255
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :type => :int, :default => "hello" }
|
256
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :String, :default => 4 }
|
257
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :String, :default => ["hi"] }
|
258
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :type => :ints, :default => [3.14] }
|
200
259
|
|
201
260
|
@p.opt "argsi", "desc", :type => :int, :default => 4
|
202
261
|
@p.opt "argsf", "desc", :type => :float, :default => 3.14
|
@@ -239,10 +298,11 @@ class ParserTest < ::MiniTest::Test
|
|
239
298
|
@p.opt "argmf", "desc", :type => :floats, :default => []
|
240
299
|
@p.opt "argmd", "desc", :type => :dates, :default => []
|
241
300
|
@p.opt "argms", "desc", :type => :strings, :default => []
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
301
|
+
err_regex = %r/multiple argument type must be plural/
|
302
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badi", "desc", :type => :int, :default => [] }
|
303
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badf", "desc", :type => :float, :default => [] }
|
304
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badd", "desc", :type => :date, :default => [] }
|
305
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "bads", "desc", :type => :string, :default => [] }
|
246
306
|
opts = @p.parse([])
|
247
307
|
assert_equal(opts["argmi"], [])
|
248
308
|
assert_equal(opts["argmf"], [])
|
@@ -255,18 +315,20 @@ class ParserTest < ::MiniTest::Test
|
|
255
315
|
@p.opt "goodarg2", "desc", :long => "--two"
|
256
316
|
@p.opt "goodarg3", "desc", :long => "arg-3"
|
257
317
|
@p.opt "goodarg4", "desc", :long => "--good-arg-four"
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
318
|
+
err_regex = /invalid long option name/
|
319
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :long => "" }
|
320
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :long => "--" }
|
321
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :long => "-one" }
|
322
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg4", "desc", :long => "---toomany" }
|
262
323
|
end
|
263
324
|
|
264
325
|
def test_short_detects_bad_names
|
265
326
|
@p.opt "goodarg", "desc", :short => "a"
|
266
327
|
@p.opt "goodarg2", "desc", :short => "-b"
|
267
|
-
|
268
|
-
|
269
|
-
|
328
|
+
err_regex = /invalid short option name/
|
329
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :short => "" }
|
330
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg2", "desc", :short => "-ab" }
|
331
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg3", "desc", :short => "--t" }
|
270
332
|
end
|
271
333
|
|
272
334
|
def test_short_names_created_automatically
|
@@ -310,25 +372,29 @@ class ParserTest < ::MiniTest::Test
|
|
310
372
|
@p.educate sio
|
311
373
|
assert sio.string =~ /--arg\s+desc/
|
312
374
|
|
313
|
-
|
375
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-a'/) { @p.parse %w(-a) }
|
314
376
|
end
|
315
377
|
|
316
378
|
## two args can't have the same name
|
317
379
|
def test_conflicting_names_are_detected
|
318
380
|
@p.opt "goodarg"
|
319
|
-
|
381
|
+
err_regex = /you already have an argument named 'goodarg'/
|
382
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "goodarg" }
|
320
383
|
end
|
321
384
|
|
322
385
|
## two args can't have the same :long
|
323
386
|
def test_conflicting_longs_detected
|
324
387
|
@p.opt "goodarg", "desc", :long => "--goodarg"
|
325
|
-
|
388
|
+
err_regex = /long option name \"goodarg\" is already taken/
|
389
|
+
|
390
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :long => "--goodarg" }
|
326
391
|
end
|
327
392
|
|
328
393
|
## two args can't have the same :short
|
329
394
|
def test_conflicting_shorts_detected
|
330
395
|
@p.opt "goodarg", "desc", :short => "-g"
|
331
|
-
|
396
|
+
err_regex = /short option name \"g\" is already taken/
|
397
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :short => "-g" }
|
332
398
|
end
|
333
399
|
|
334
400
|
## note: this behavior has changed in optimist 2.0!
|
@@ -397,7 +463,7 @@ class ParserTest < ::MiniTest::Test
|
|
397
463
|
assert_equal false, opts[:no_default_true]
|
398
464
|
|
399
465
|
## disallow double negatives for reasons of sanity preservation
|
400
|
-
|
466
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--no-default-true'/) { @p.parse %w(--no-no-default-true) }
|
401
467
|
end
|
402
468
|
|
403
469
|
def test_short_options_combine
|
@@ -420,8 +486,9 @@ class ParserTest < ::MiniTest::Test
|
|
420
486
|
assert_equal true, opts[:arg2]
|
421
487
|
assert_equal 4, opts[:arg3]
|
422
488
|
|
423
|
-
|
424
|
-
|
489
|
+
err_regex = /option '-c' needs a parameter/
|
490
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-cab 4) }
|
491
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-cba 4) }
|
425
492
|
end
|
426
493
|
|
427
494
|
def test_doubledash_ends_option_processing
|
@@ -508,13 +575,15 @@ Options:
|
|
508
575
|
assert_equal(-0.1, opts[:arg])
|
509
576
|
opts = @p.parse %w(-f -.1)
|
510
577
|
assert_equal(-0.1, opts[:arg])
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
578
|
+
err_regex = %r/option 'arg' needs a floating-point number/
|
579
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f a) }
|
580
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1a) }
|
581
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1.a) }
|
582
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f a.1) }
|
583
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f 1.0.0) }
|
584
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f .) }
|
585
|
+
err_regex = %r/unknown argument '-.'/
|
586
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-f -.) }
|
518
587
|
end
|
519
588
|
|
520
589
|
def test_floating_point_formatting_default
|
@@ -532,23 +601,30 @@ Options:
|
|
532
601
|
end
|
533
602
|
|
534
603
|
def test_short_options_cant_be_numeric
|
535
|
-
|
604
|
+
err_regex = %r/short option name '1' can't be a number or a dash/
|
605
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt :arg, "desc", :short => "-1" }
|
536
606
|
@p.opt :a1b, "desc"
|
537
607
|
@p.opt :a2b, "desc"
|
538
|
-
|
608
|
+
@p.parse []
|
609
|
+
# testing private interface to ensure default
|
610
|
+
# short options did not become numeric
|
611
|
+
assert_equal @p.specs[:a1b].short.chars.first, 'a'
|
612
|
+
assert_equal @p.specs[:a2b].short.chars.first, 'b'
|
539
613
|
end
|
540
614
|
|
541
615
|
def test_short_options_can_be_weird
|
542
616
|
@p.opt :arg1, "desc", :short => "#"
|
543
617
|
@p.opt :arg2, "desc", :short => "."
|
544
|
-
|
618
|
+
err_regex = %r/short option name '-' can't be a number or a dash/
|
619
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt :arg3, "desc", :short => "-" }
|
545
620
|
end
|
546
621
|
|
547
622
|
def test_options_cant_be_set_multiple_times_if_not_specified
|
548
623
|
@p.opt :arg, "desc", :short => "-x"
|
549
624
|
@p.parse %w(-x)
|
550
|
-
|
551
|
-
|
625
|
+
err_regex = /option '-x' specified multiple times/
|
626
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-x -x) }
|
627
|
+
assert_raises_errmatch(CommandlineError, err_regex) { @p.parse %w(-xx) }
|
552
628
|
end
|
553
629
|
|
554
630
|
def test_options_can_be_set_multiple_times_if_specified
|
@@ -632,7 +708,7 @@ Options:
|
|
632
708
|
assert_equal [4, 6, 9], opts[:arg3]
|
633
709
|
assert_equal [3.14, 2.41], opts[:arg4]
|
634
710
|
|
635
|
-
|
711
|
+
assert_raises_errmatch(CommandlineError, /option '-c' needs a parameter/) { opts = @p.parse %w(-abcd 3.14 2.41) }
|
636
712
|
end
|
637
713
|
|
638
714
|
def test_long_options_with_multiple_options
|
@@ -712,7 +788,7 @@ Options:
|
|
712
788
|
|
713
789
|
def test_auto_generated_long_names_convert_underscores_to_hyphens
|
714
790
|
@p.opt :hello_there
|
715
|
-
assert_equal "hello-there", @p.specs[:hello_there].long
|
791
|
+
assert_equal "hello-there", @p.specs[:hello_there].long.long
|
716
792
|
end
|
717
793
|
|
718
794
|
def test_arguments_passed_through_block
|
@@ -724,126 +800,37 @@ Options:
|
|
724
800
|
assert_equal @goat, boat
|
725
801
|
end
|
726
802
|
|
803
|
+
## test-only access reader method so that we dont have to
|
804
|
+
## expose settings in the public API.
|
805
|
+
class Optimist::Parser
|
806
|
+
def get_settings_for_testing ; return @settings ;end
|
807
|
+
end
|
808
|
+
|
809
|
+
def test_two_arguments_passed_through_block
|
810
|
+
newp = Parser.new(:abcd => 123, :efgh => "other" ) do |i|
|
811
|
+
end
|
812
|
+
assert_equal newp.get_settings_for_testing[:abcd], 123
|
813
|
+
assert_equal newp.get_settings_for_testing[:efgh], "other"
|
814
|
+
end
|
815
|
+
|
816
|
+
|
727
817
|
def test_version_and_help_override_errors
|
728
818
|
@p.opt :asdf, "desc", :type => String
|
729
819
|
@p.version "version"
|
730
820
|
@p.parse %w(--asdf goat)
|
731
|
-
|
821
|
+
assert_raises_errmatch(CommandlineError, /option '--asdf' needs a parameter/) { @p.parse %w(--asdf) }
|
732
822
|
assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
|
733
823
|
assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
|
734
824
|
end
|
735
825
|
|
736
|
-
def test_conflicts
|
737
|
-
@p.opt :one
|
738
|
-
assert_raises(ArgumentError) { @p.conflicts :one, :two }
|
739
|
-
@p.opt :two
|
740
|
-
@p.conflicts :one, :two
|
741
|
-
@p.parse %w(--one)
|
742
|
-
@p.parse %w(--two)
|
743
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --two) }
|
744
|
-
|
745
|
-
@p.opt :hello
|
746
|
-
@p.opt :yellow
|
747
|
-
@p.opt :mellow
|
748
|
-
@p.opt :jello
|
749
|
-
@p.conflicts :hello, :yellow, :mellow, :jello
|
750
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
|
751
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
752
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
753
|
-
|
754
|
-
@p.parse %w(--hello)
|
755
|
-
@p.parse %w(--jello)
|
756
|
-
@p.parse %w(--yellow)
|
757
|
-
@p.parse %w(--mellow)
|
758
|
-
|
759
|
-
@p.parse %w(--mellow --one)
|
760
|
-
@p.parse %w(--mellow --two)
|
761
|
-
|
762
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
|
763
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
|
764
|
-
end
|
765
|
-
|
766
|
-
def test_either
|
767
|
-
@p.opt :one
|
768
|
-
assert_raises(ArgumentError) { @p.either :one, :two }
|
769
|
-
@p.opt :two
|
770
|
-
@p.either :one, :two
|
771
|
-
@p.parse %w(--one)
|
772
|
-
@p.parse %w(--two)
|
773
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --two) }
|
774
|
-
assert_raises(CommandlineError) { @p.parse %w() }
|
775
|
-
|
776
|
-
@p.opt :hello
|
777
|
-
@p.opt :yellow
|
778
|
-
@p.opt :mellow
|
779
|
-
@p.opt :jello
|
780
|
-
@p.either :hello, :yellow, :mellow, :jello
|
781
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
|
782
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
783
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
784
|
-
|
785
|
-
@p.parse %w(--hello --one)
|
786
|
-
@p.parse %w(--jello --two)
|
787
|
-
@p.parse %w(--mellow --one)
|
788
|
-
@p.parse %w(--mellow --two)
|
789
|
-
|
790
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
|
791
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
|
792
|
-
end
|
793
|
-
|
794
|
-
def test_conflict_error_messages
|
795
|
-
@p.opt :one
|
796
|
-
@p.opt "two"
|
797
|
-
@p.conflicts :one, "two"
|
798
|
-
|
799
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one --two) }
|
800
|
-
end
|
801
|
-
|
802
|
-
def test_depends
|
803
|
-
@p.opt :one
|
804
|
-
assert_raises(ArgumentError) { @p.depends :one, :two }
|
805
|
-
@p.opt :two
|
806
|
-
@p.depends :one, :two
|
807
|
-
@p.parse %w(--one --two)
|
808
|
-
assert_raises(CommandlineError) { @p.parse %w(--one) }
|
809
|
-
assert_raises(CommandlineError) { @p.parse %w(--two) }
|
810
|
-
|
811
|
-
@p.opt :hello
|
812
|
-
@p.opt :yellow
|
813
|
-
@p.opt :mellow
|
814
|
-
@p.opt :jello
|
815
|
-
@p.depends :hello, :yellow, :mellow, :jello
|
816
|
-
@p.parse %w(--hello --yellow --mellow --jello)
|
817
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
818
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
819
|
-
|
820
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello) }
|
821
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow) }
|
822
|
-
|
823
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two)
|
824
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two a b c)
|
825
|
-
|
826
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello --one) }
|
827
|
-
end
|
828
|
-
|
829
|
-
def test_depend_error_messages
|
830
|
-
@p.opt :one
|
831
|
-
@p.opt "two"
|
832
|
-
@p.depends :one, "two"
|
833
|
-
|
834
|
-
@p.parse %w(--one --two)
|
835
|
-
|
836
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one) }
|
837
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--two) }
|
838
|
-
end
|
839
826
|
|
840
827
|
## courtesy neill zero
|
841
828
|
def test_two_required_one_missing_accuses_correctly
|
842
829
|
@p.opt "arg1", "desc1", :required => true
|
843
830
|
@p.opt "arg2", "desc2", :required => true
|
844
831
|
|
845
|
-
|
846
|
-
|
832
|
+
assert_raises_errmatch(CommandlineError, /arg2/) { @p.parse(%w(--arg1)) }
|
833
|
+
assert_raises_errmatch(CommandlineError, /arg1/) { @p.parse(%w(--arg2)) }
|
847
834
|
@p.parse(%w(--arg1 --arg2))
|
848
835
|
end
|
849
836
|
|
@@ -1004,8 +991,11 @@ Options:
|
|
1004
991
|
|
1005
992
|
opts = @p.parse %w(--arg3 stdin)
|
1006
993
|
assert_equal $stdin, opts[:arg3]
|
1007
|
-
|
1008
|
-
|
994
|
+
|
995
|
+
err_regex = %r/file or url for option 'arg' cannot be opened: No such file or directory/
|
996
|
+
assert_raises_errmatch(CommandlineError, err_regex) {
|
997
|
+
opts = @p.parse %w(--arg /fdasfasef/fessafef/asdfasdfa/fesasf)
|
998
|
+
}
|
1009
999
|
end
|
1010
1000
|
|
1011
1001
|
def test_openstruct_style_access
|
@@ -1106,6 +1096,86 @@ Options:
|
|
1106
1096
|
assert opts[:ccd]
|
1107
1097
|
end
|
1108
1098
|
|
1099
|
+
def test_short_opts_not_implicitly_created
|
1100
|
+
newp = Parser.new(implicit_short_opts: false)
|
1101
|
+
newp.opt :user1, "user1"
|
1102
|
+
newp.opt :bag, "bag", :short => 'b'
|
1103
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-u'/) do
|
1104
|
+
newp.parse %w(-u)
|
1105
|
+
end
|
1106
|
+
opts = newp.parse %w(--user1)
|
1107
|
+
assert opts[:user1]
|
1108
|
+
opts = newp.parse %w(-b)
|
1109
|
+
assert opts[:bag]
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def test_short_opts_not_implicit_help_ver
|
1113
|
+
# When implicit_short_opts is false this implies the short options
|
1114
|
+
# for the built-in help/version are also not created.
|
1115
|
+
newp = Parser.new(implicit_short_opts: false)
|
1116
|
+
newp.opt :abc, "abc"
|
1117
|
+
newp.version "3.4.5"
|
1118
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-h'/) do
|
1119
|
+
newp.parse %w(-h)
|
1120
|
+
end
|
1121
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-v'/) do
|
1122
|
+
newp.parse %w(-v)
|
1123
|
+
end
|
1124
|
+
assert_raises(HelpNeeded) do
|
1125
|
+
newp.parse %w(--help)
|
1126
|
+
end
|
1127
|
+
assert_raises(VersionNeeded) do
|
1128
|
+
newp.parse %w(--version)
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def test_inexact_match
|
1133
|
+
newp = Parser.new(exact_match: false)
|
1134
|
+
newp.opt :liberation, "liberate something", :type => :int
|
1135
|
+
newp.opt :evaluate, "evaluate something", :type => :string
|
1136
|
+
opts = newp.parse %w(--lib 5 --ev bar)
|
1137
|
+
assert_equal 5, opts[:liberation]
|
1138
|
+
assert_equal 'bar', opts[:evaluate]
|
1139
|
+
assert_nil opts[:eval]
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def test_exact_match
|
1143
|
+
newp = Parser.new()
|
1144
|
+
newp.opt :liberation, "liberate something", :type => :int
|
1145
|
+
newp.opt :evaluate, "evaluate something", :type => :string
|
1146
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--lib'/) do
|
1147
|
+
newp.parse %w(--lib 5)
|
1148
|
+
end
|
1149
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--ev'/) do
|
1150
|
+
newp.parse %w(--ev bar)
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def test_inexact_collision
|
1155
|
+
newp = Parser.new(exact_match: false)
|
1156
|
+
newp.opt :bookname, "name of a book", :type => :string
|
1157
|
+
newp.opt :bookcost, "cost of the book", :type => :string
|
1158
|
+
opts = newp.parse %w(--bookn hairy_potsworth --bookc 10)
|
1159
|
+
assert_equal 'hairy_potsworth', opts[:bookname]
|
1160
|
+
assert_equal '10', opts[:bookcost]
|
1161
|
+
assert_raises_errmatch(CommandlineError, /ambiguous option '--book' matched keys \(bookname,bookcost\)/) do
|
1162
|
+
newp.parse %w(--book 5) # ambiguous
|
1163
|
+
end
|
1164
|
+
## partial match causes 'specified multiple times' error
|
1165
|
+
assert_raises_errmatch(CommandlineError, /specified multiple times/) do
|
1166
|
+
newp.parse %w(--bookc 17 --bookcost 22)
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def test_inexact_collision_with_exact
|
1171
|
+
newp = Parser.new(exact_match: false)
|
1172
|
+
newp.opt :book, "name of a book", :type => :string, :default => "ABC"
|
1173
|
+
newp.opt :bookcost, "cost of the book", :type => :int, :default => 5
|
1174
|
+
opts = newp.parse %w(--book warthog --bookc 3)
|
1175
|
+
assert_equal 'warthog', opts[:book]
|
1176
|
+
assert_equal 3, opts[:bookcost]
|
1177
|
+
end
|
1178
|
+
|
1109
1179
|
def test_accepts_arguments_with_spaces
|
1110
1180
|
@p.opt :arg1, "arg", :type => String
|
1111
1181
|
@p.opt :arg2, "arg2", :type => String
|
@@ -1163,7 +1233,7 @@ Options:
|
|
1163
1233
|
end
|
1164
1234
|
|
1165
1235
|
def test_simple_interface_handles_die
|
1166
|
-
assert_stderr do
|
1236
|
+
assert_stderr(/Error: argument --potato is invalid/) do
|
1167
1237
|
::Optimist::options(%w(--potato)) do
|
1168
1238
|
opt :potato
|
1169
1239
|
end
|
@@ -1172,7 +1242,7 @@ Options:
|
|
1172
1242
|
end
|
1173
1243
|
|
1174
1244
|
def test_simple_interface_handles_die_without_message
|
1175
|
-
assert_stderr(/Error
|
1245
|
+
assert_stderr(/Error: potato\./) do
|
1176
1246
|
::Optimist::options(%w(--potato)) do
|
1177
1247
|
opt :potato
|
1178
1248
|
end
|
@@ -1181,7 +1251,7 @@ Options:
|
|
1181
1251
|
end
|
1182
1252
|
|
1183
1253
|
def test_invalid_option_with_simple_interface
|
1184
|
-
assert_stderr do
|
1254
|
+
assert_stderr(/Error: unknown argument \'--potato\'\./) do
|
1185
1255
|
assert_raises(SystemExit) do
|
1186
1256
|
::Optimist.options(%w(--potato))
|
1187
1257
|
end
|
@@ -1197,7 +1267,7 @@ Options:
|
|
1197
1267
|
end
|
1198
1268
|
|
1199
1269
|
def test_supports_callback_inline
|
1200
|
-
|
1270
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1201
1271
|
@p.opt :cb1 do |vals|
|
1202
1272
|
raise "good"
|
1203
1273
|
end
|
@@ -1206,7 +1276,7 @@ Options:
|
|
1206
1276
|
end
|
1207
1277
|
|
1208
1278
|
def test_supports_callback_param
|
1209
|
-
|
1279
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1210
1280
|
@p.opt :cb1, "with callback", :callback => lambda { |vals| raise "good" }
|
1211
1281
|
@p.parse(%w(--cb1))
|
1212
1282
|
end
|
@@ -1261,6 +1331,37 @@ Options:
|
|
1261
1331
|
assert opts[:arg1]
|
1262
1332
|
assert_equal %w{-bu potato}, @p.leftovers
|
1263
1333
|
end
|
1334
|
+
|
1335
|
+
# Due to strangeness in how the cloaker works, there were
|
1336
|
+
# cases where Optimist.parse would work, but Optimist.options
|
1337
|
+
# did not, depending on arguments given to the function.
|
1338
|
+
# These serve to validate different args given to Optimist.options
|
1339
|
+
def test_options_takes_hashy_settings
|
1340
|
+
passargs_copy = []
|
1341
|
+
settings_copy = []
|
1342
|
+
::Optimist.options(%w(--wig --pig), :fizz=>:buzz, :bear=>:cat) do |*passargs|
|
1343
|
+
opt :wig
|
1344
|
+
opt :pig
|
1345
|
+
passargs_copy = passargs.dup
|
1346
|
+
settings_copy = @settings
|
1347
|
+
end
|
1348
|
+
assert_equal [], passargs_copy
|
1349
|
+
assert_equal settings_copy[:fizz], :buzz
|
1350
|
+
assert_equal settings_copy[:bear], :cat
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
def test_options_takes_some_other_data
|
1354
|
+
passargs_copy = []
|
1355
|
+
settings_copy = []
|
1356
|
+
::Optimist.options(%w(--nose --close), 1, 2, 3) do |*passargs|
|
1357
|
+
opt :nose
|
1358
|
+
opt :close
|
1359
|
+
passargs_copy = passargs.dup
|
1360
|
+
settings_copy = @settings
|
1361
|
+
end
|
1362
|
+
assert_equal [1,2,3], passargs_copy
|
1363
|
+
assert_equal(Optimist::Parser::DEFAULT_SETTINGS, settings_copy)
|
1364
|
+
end
|
1264
1365
|
end
|
1265
1366
|
|
1266
1367
|
end
|