optimist 3.0.1 → 3.2.0
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/.codeclimate.yml +16 -0
- data/.github/workflows/ci.yaml +36 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_cc.yml +4 -0
- data/.rubocop_local.yml +0 -0
- data/.whitesource +3 -0
- data/CHANGELOG.md +232 -0
- data/README.md +2 -3
- 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 +352 -90
- data/optimist.gemspec +4 -3
- 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 +295 -148
- 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 +57 -20
- data/.travis.yml +0 -14
- 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"], [])
|
@@ -253,18 +313,22 @@ class ParserTest < ::MiniTest::Test
|
|
253
313
|
def test_long_detects_bad_names
|
254
314
|
@p.opt "goodarg", "desc", :long => "none"
|
255
315
|
@p.opt "goodarg2", "desc", :long => "--two"
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
316
|
+
@p.opt "goodarg3", "desc", :long => "arg-3"
|
317
|
+
@p.opt "goodarg4", "desc", :long => "--good-arg-four"
|
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" }
|
260
323
|
end
|
261
324
|
|
262
325
|
def test_short_detects_bad_names
|
263
326
|
@p.opt "goodarg", "desc", :short => "a"
|
264
327
|
@p.opt "goodarg2", "desc", :short => "-b"
|
265
|
-
|
266
|
-
|
267
|
-
|
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" }
|
268
332
|
end
|
269
333
|
|
270
334
|
def test_short_names_created_automatically
|
@@ -308,25 +372,29 @@ class ParserTest < ::MiniTest::Test
|
|
308
372
|
@p.educate sio
|
309
373
|
assert sio.string =~ /--arg\s+desc/
|
310
374
|
|
311
|
-
|
375
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '-a'/) { @p.parse %w(-a) }
|
312
376
|
end
|
313
377
|
|
314
378
|
## two args can't have the same name
|
315
379
|
def test_conflicting_names_are_detected
|
316
380
|
@p.opt "goodarg"
|
317
|
-
|
381
|
+
err_regex = /you already have an argument named 'goodarg'/
|
382
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "goodarg" }
|
318
383
|
end
|
319
384
|
|
320
385
|
## two args can't have the same :long
|
321
386
|
def test_conflicting_longs_detected
|
322
387
|
@p.opt "goodarg", "desc", :long => "--goodarg"
|
323
|
-
|
388
|
+
err_regex = /long option name \"goodarg\" is already taken/
|
389
|
+
|
390
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :long => "--goodarg" }
|
324
391
|
end
|
325
392
|
|
326
393
|
## two args can't have the same :short
|
327
394
|
def test_conflicting_shorts_detected
|
328
395
|
@p.opt "goodarg", "desc", :short => "-g"
|
329
|
-
|
396
|
+
err_regex = /short option name \"g\" is already taken/
|
397
|
+
assert_raises_errmatch(ArgumentError, err_regex) { @p.opt "badarg", "desc", :short => "-g" }
|
330
398
|
end
|
331
399
|
|
332
400
|
## note: this behavior has changed in optimist 2.0!
|
@@ -347,6 +415,14 @@ class ParserTest < ::MiniTest::Test
|
|
347
415
|
assert_equal true, opts[:defaultfalse]
|
348
416
|
assert_equal true, opts[:defaulttrue]
|
349
417
|
|
418
|
+
## using short form turns them all on, regardless of default
|
419
|
+
#
|
420
|
+
# (matches positve "non-no" long form)
|
421
|
+
opts = @p.parse %w(-d -e -f)
|
422
|
+
assert_equal true, opts[:defaultnone]
|
423
|
+
assert_equal true, opts[:defaultfalse]
|
424
|
+
assert_equal true, opts[:defaulttrue]
|
425
|
+
|
350
426
|
## using --no- form turns them off, regardless of default
|
351
427
|
opts = @p.parse %w(--no-defaultfalse --no-defaulttrue --no-defaultnone)
|
352
428
|
assert_equal false, opts[:defaultnone]
|
@@ -378,8 +454,16 @@ class ParserTest < ::MiniTest::Test
|
|
378
454
|
assert_equal false, opts[:no_default_false]
|
379
455
|
assert_equal false, opts[:no_default_true]
|
380
456
|
|
457
|
+
## using short form turns them all off, regardless of default
|
458
|
+
#
|
459
|
+
# (matches positve "non-no" long form)
|
460
|
+
opts = @p.parse %w(-n -o -d)
|
461
|
+
assert_equal false, opts[:no_default_none]
|
462
|
+
assert_equal false, opts[:no_default_false]
|
463
|
+
assert_equal false, opts[:no_default_true]
|
464
|
+
|
381
465
|
## disallow double negatives for reasons of sanity preservation
|
382
|
-
|
466
|
+
assert_raises_errmatch(CommandlineError, /unknown argument '--no-default-true'/) { @p.parse %w(--no-no-default-true) }
|
383
467
|
end
|
384
468
|
|
385
469
|
def test_short_options_combine
|
@@ -402,8 +486,9 @@ class ParserTest < ::MiniTest::Test
|
|
402
486
|
assert_equal true, opts[:arg2]
|
403
487
|
assert_equal 4, opts[:arg3]
|
404
488
|
|
405
|
-
|
406
|
-
|
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) }
|
407
492
|
end
|
408
493
|
|
409
494
|
def test_doubledash_ends_option_processing
|
@@ -490,13 +575,15 @@ Options:
|
|
490
575
|
assert_equal(-0.1, opts[:arg])
|
491
576
|
opts = @p.parse %w(-f -.1)
|
492
577
|
assert_equal(-0.1, opts[:arg])
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
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 -.) }
|
500
587
|
end
|
501
588
|
|
502
589
|
def test_floating_point_formatting_default
|
@@ -514,23 +601,30 @@ Options:
|
|
514
601
|
end
|
515
602
|
|
516
603
|
def test_short_options_cant_be_numeric
|
517
|
-
|
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" }
|
518
606
|
@p.opt :a1b, "desc"
|
519
607
|
@p.opt :a2b, "desc"
|
520
|
-
|
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'
|
521
613
|
end
|
522
614
|
|
523
615
|
def test_short_options_can_be_weird
|
524
616
|
@p.opt :arg1, "desc", :short => "#"
|
525
617
|
@p.opt :arg2, "desc", :short => "."
|
526
|
-
|
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 => "-" }
|
527
620
|
end
|
528
621
|
|
529
622
|
def test_options_cant_be_set_multiple_times_if_not_specified
|
530
623
|
@p.opt :arg, "desc", :short => "-x"
|
531
624
|
@p.parse %w(-x)
|
532
|
-
|
533
|
-
|
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) }
|
534
628
|
end
|
535
629
|
|
536
630
|
def test_options_can_be_set_multiple_times_if_specified
|
@@ -614,7 +708,7 @@ Options:
|
|
614
708
|
assert_equal [4, 6, 9], opts[:arg3]
|
615
709
|
assert_equal [3.14, 2.41], opts[:arg4]
|
616
710
|
|
617
|
-
|
711
|
+
assert_raises_errmatch(CommandlineError, /option '-c' needs a parameter/) { opts = @p.parse %w(-abcd 3.14 2.41) }
|
618
712
|
end
|
619
713
|
|
620
714
|
def test_long_options_with_multiple_options
|
@@ -694,7 +788,7 @@ Options:
|
|
694
788
|
|
695
789
|
def test_auto_generated_long_names_convert_underscores_to_hyphens
|
696
790
|
@p.opt :hello_there
|
697
|
-
assert_equal "hello-there", @p.specs[:hello_there].long
|
791
|
+
assert_equal "hello-there", @p.specs[:hello_there].long.long
|
698
792
|
end
|
699
793
|
|
700
794
|
def test_arguments_passed_through_block
|
@@ -706,98 +800,37 @@ Options:
|
|
706
800
|
assert_equal @goat, boat
|
707
801
|
end
|
708
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
|
+
|
709
817
|
def test_version_and_help_override_errors
|
710
818
|
@p.opt :asdf, "desc", :type => String
|
711
819
|
@p.version "version"
|
712
820
|
@p.parse %w(--asdf goat)
|
713
|
-
|
821
|
+
assert_raises_errmatch(CommandlineError, /option '--asdf' needs a parameter/) { @p.parse %w(--asdf) }
|
714
822
|
assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
|
715
823
|
assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
|
716
824
|
end
|
717
825
|
|
718
|
-
def test_conflicts
|
719
|
-
@p.opt :one
|
720
|
-
assert_raises(ArgumentError) { @p.conflicts :one, :two }
|
721
|
-
@p.opt :two
|
722
|
-
@p.conflicts :one, :two
|
723
|
-
@p.parse %w(--one)
|
724
|
-
@p.parse %w(--two)
|
725
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --two) }
|
726
|
-
|
727
|
-
@p.opt :hello
|
728
|
-
@p.opt :yellow
|
729
|
-
@p.opt :mellow
|
730
|
-
@p.opt :jello
|
731
|
-
@p.conflicts :hello, :yellow, :mellow, :jello
|
732
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --yellow --mellow --jello) }
|
733
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
734
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
735
|
-
|
736
|
-
@p.parse %w(--hello)
|
737
|
-
@p.parse %w(--jello)
|
738
|
-
@p.parse %w(--yellow)
|
739
|
-
@p.parse %w(--mellow)
|
740
|
-
|
741
|
-
@p.parse %w(--mellow --one)
|
742
|
-
@p.parse %w(--mellow --two)
|
743
|
-
|
744
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello) }
|
745
|
-
assert_raises(CommandlineError) { @p.parse %w(--one --mellow --two --jello) }
|
746
|
-
end
|
747
|
-
|
748
|
-
def test_conflict_error_messages
|
749
|
-
@p.opt :one
|
750
|
-
@p.opt "two"
|
751
|
-
@p.conflicts :one, "two"
|
752
|
-
|
753
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one --two) }
|
754
|
-
end
|
755
|
-
|
756
|
-
def test_depends
|
757
|
-
@p.opt :one
|
758
|
-
assert_raises(ArgumentError) { @p.depends :one, :two }
|
759
|
-
@p.opt :two
|
760
|
-
@p.depends :one, :two
|
761
|
-
@p.parse %w(--one --two)
|
762
|
-
assert_raises(CommandlineError) { @p.parse %w(--one) }
|
763
|
-
assert_raises(CommandlineError) { @p.parse %w(--two) }
|
764
|
-
|
765
|
-
@p.opt :hello
|
766
|
-
@p.opt :yellow
|
767
|
-
@p.opt :mellow
|
768
|
-
@p.opt :jello
|
769
|
-
@p.depends :hello, :yellow, :mellow, :jello
|
770
|
-
@p.parse %w(--hello --yellow --mellow --jello)
|
771
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --mellow --jello) }
|
772
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello --jello) }
|
773
|
-
|
774
|
-
assert_raises(CommandlineError) { @p.parse %w(--hello) }
|
775
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow) }
|
776
|
-
|
777
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two)
|
778
|
-
@p.parse %w(--hello --yellow --mellow --jello --one --two a b c)
|
779
|
-
|
780
|
-
assert_raises(CommandlineError) { @p.parse %w(--mellow --two --jello --one) }
|
781
|
-
end
|
782
|
-
|
783
|
-
def test_depend_error_messages
|
784
|
-
@p.opt :one
|
785
|
-
@p.opt "two"
|
786
|
-
@p.depends :one, "two"
|
787
|
-
|
788
|
-
@p.parse %w(--one --two)
|
789
|
-
|
790
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--one) }
|
791
|
-
assert_raises(CommandlineError, /--one.*--two/) { @p.parse %w(--two) }
|
792
|
-
end
|
793
826
|
|
794
827
|
## courtesy neill zero
|
795
828
|
def test_two_required_one_missing_accuses_correctly
|
796
829
|
@p.opt "arg1", "desc1", :required => true
|
797
830
|
@p.opt "arg2", "desc2", :required => true
|
798
831
|
|
799
|
-
|
800
|
-
|
832
|
+
assert_raises_errmatch(CommandlineError, /arg2/) { @p.parse(%w(--arg1)) }
|
833
|
+
assert_raises_errmatch(CommandlineError, /arg1/) { @p.parse(%w(--arg2)) }
|
801
834
|
@p.parse(%w(--arg1 --arg2))
|
802
835
|
end
|
803
836
|
|
@@ -958,8 +991,11 @@ Options:
|
|
958
991
|
|
959
992
|
opts = @p.parse %w(--arg3 stdin)
|
960
993
|
assert_equal $stdin, opts[:arg3]
|
961
|
-
|
962
|
-
|
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
|
+
}
|
963
999
|
end
|
964
1000
|
|
965
1001
|
def test_openstruct_style_access
|
@@ -1060,6 +1096,86 @@ Options:
|
|
1060
1096
|
assert opts[:ccd]
|
1061
1097
|
end
|
1062
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
|
+
|
1063
1179
|
def test_accepts_arguments_with_spaces
|
1064
1180
|
@p.opt :arg1, "arg", :type => String
|
1065
1181
|
@p.opt :arg2, "arg2", :type => String
|
@@ -1117,7 +1233,7 @@ Options:
|
|
1117
1233
|
end
|
1118
1234
|
|
1119
1235
|
def test_simple_interface_handles_die
|
1120
|
-
assert_stderr do
|
1236
|
+
assert_stderr(/Error: argument --potato is invalid/) do
|
1121
1237
|
::Optimist::options(%w(--potato)) do
|
1122
1238
|
opt :potato
|
1123
1239
|
end
|
@@ -1126,7 +1242,7 @@ Options:
|
|
1126
1242
|
end
|
1127
1243
|
|
1128
1244
|
def test_simple_interface_handles_die_without_message
|
1129
|
-
assert_stderr(/Error
|
1245
|
+
assert_stderr(/Error: potato\./) do
|
1130
1246
|
::Optimist::options(%w(--potato)) do
|
1131
1247
|
opt :potato
|
1132
1248
|
end
|
@@ -1135,7 +1251,7 @@ Options:
|
|
1135
1251
|
end
|
1136
1252
|
|
1137
1253
|
def test_invalid_option_with_simple_interface
|
1138
|
-
assert_stderr do
|
1254
|
+
assert_stderr(/Error: unknown argument \'--potato\'\./) do
|
1139
1255
|
assert_raises(SystemExit) do
|
1140
1256
|
::Optimist.options(%w(--potato))
|
1141
1257
|
end
|
@@ -1151,7 +1267,7 @@ Options:
|
|
1151
1267
|
end
|
1152
1268
|
|
1153
1269
|
def test_supports_callback_inline
|
1154
|
-
|
1270
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1155
1271
|
@p.opt :cb1 do |vals|
|
1156
1272
|
raise "good"
|
1157
1273
|
end
|
@@ -1160,7 +1276,7 @@ Options:
|
|
1160
1276
|
end
|
1161
1277
|
|
1162
1278
|
def test_supports_callback_param
|
1163
|
-
|
1279
|
+
assert_raises_errmatch(RuntimeError, "good") do
|
1164
1280
|
@p.opt :cb1, "with callback", :callback => lambda { |vals| raise "good" }
|
1165
1281
|
@p.parse(%w(--cb1))
|
1166
1282
|
end
|
@@ -1215,6 +1331,37 @@ Options:
|
|
1215
1331
|
assert opts[:arg1]
|
1216
1332
|
assert_equal %w{-bu potato}, @p.leftovers
|
1217
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
|
1218
1365
|
end
|
1219
1366
|
|
1220
1367
|
end
|