methadone-rehab 1.9.2
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 +7 -0
- data/.gitignore +15 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +11 -0
- data/CHANGES.md +66 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +201 -0
- data/README.rdoc +179 -0
- data/Rakefile +98 -0
- data/TODO.md +3 -0
- data/bin/methadone +157 -0
- data/features/bootstrap.feature +169 -0
- data/features/license.feature +43 -0
- data/features/multilevel_commands.feature +125 -0
- data/features/readme.feature +26 -0
- data/features/rspec_support.feature +27 -0
- data/features/step_definitions/bootstrap_steps.rb +47 -0
- data/features/step_definitions/license_steps.rb +30 -0
- data/features/step_definitions/readme_steps.rb +26 -0
- data/features/step_definitions/version_steps.rb +4 -0
- data/features/support/env.rb +26 -0
- data/features/version.feature +17 -0
- data/lib/methadone.rb +15 -0
- data/lib/methadone/argv_parser.rb +50 -0
- data/lib/methadone/cli.rb +124 -0
- data/lib/methadone/cli_logger.rb +133 -0
- data/lib/methadone/cli_logging.rb +138 -0
- data/lib/methadone/cucumber.rb +174 -0
- data/lib/methadone/error.rb +32 -0
- data/lib/methadone/execution_strategy/base.rb +34 -0
- data/lib/methadone/execution_strategy/jvm.rb +37 -0
- data/lib/methadone/execution_strategy/mri.rb +16 -0
- data/lib/methadone/execution_strategy/open_3.rb +16 -0
- data/lib/methadone/execution_strategy/open_4.rb +22 -0
- data/lib/methadone/execution_strategy/rbx_open_4.rb +12 -0
- data/lib/methadone/exit_now.rb +40 -0
- data/lib/methadone/main.rb +1039 -0
- data/lib/methadone/process_status.rb +45 -0
- data/lib/methadone/sh.rb +223 -0
- data/lib/methadone/version.rb +3 -0
- data/methadone-rehab.gemspec +32 -0
- data/templates/full/.gitignore.erb +4 -0
- data/templates/full/README.rdoc.erb +25 -0
- data/templates/full/Rakefile.erb +74 -0
- data/templates/full/_license_head.txt.erb +2 -0
- data/templates/full/apache_LICENSE.txt.erb +203 -0
- data/templates/full/bin/executable.erb +47 -0
- data/templates/full/custom_LICENSE.txt.erb +0 -0
- data/templates/full/features/executable.feature.erb +13 -0
- data/templates/full/features/step_definitions/executable_steps.rb.erb +1 -0
- data/templates/full/features/support/env.rb.erb +16 -0
- data/templates/full/gplv2_LICENSE.txt.erb +14 -0
- data/templates/full/gplv3_LICENSE.txt.erb +15 -0
- data/templates/full/mit_LICENSE.txt.erb +7 -0
- data/templates/multicommand/bin/executable.erb +52 -0
- data/templates/multicommand/lib/command.rb.erb +40 -0
- data/templates/multicommand/lib/commands.rb.erb +7 -0
- data/templates/rspec/spec/something_spec.rb.erb +5 -0
- data/templates/test_unit/test/tc_something.rb.erb +7 -0
- data/test/base_test.rb +20 -0
- data/test/command_for_tests.sh +7 -0
- data/test/execution_strategy/test_base.rb +24 -0
- data/test/execution_strategy/test_jvm.rb +77 -0
- data/test/execution_strategy/test_mri.rb +32 -0
- data/test/execution_strategy/test_open_3.rb +70 -0
- data/test/execution_strategy/test_open_4.rb +86 -0
- data/test/execution_strategy/test_rbx_open_4.rb +25 -0
- data/test/test_cli_logger.rb +219 -0
- data/test/test_cli_logging.rb +243 -0
- data/test/test_exit_now.rb +37 -0
- data/test/test_main.rb +1213 -0
- data/test/test_multi.rb +405 -0
- data/test/test_sh.rb +404 -0
- metadata +321 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'base_test'
|
|
2
|
+
require 'methadone'
|
|
3
|
+
require 'stringio'
|
|
4
|
+
|
|
5
|
+
class TestExitNow < BaseTest
|
|
6
|
+
include Methadone
|
|
7
|
+
include Methadone::ExitNow
|
|
8
|
+
|
|
9
|
+
test_that "exit_now raises the proper error" do
|
|
10
|
+
Given {
|
|
11
|
+
@exit_code = any_int :min => 1
|
|
12
|
+
@message = any_string
|
|
13
|
+
}
|
|
14
|
+
When {
|
|
15
|
+
@code = lambda { exit_now!(@exit_code,@message) }
|
|
16
|
+
}
|
|
17
|
+
Then {
|
|
18
|
+
exception = assert_raises(Methadone::Error,&@code)
|
|
19
|
+
exception.exit_code.should == @exit_code
|
|
20
|
+
exception.message.should == @message
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test_that "exit_now without an exit code uses 1 as the exit code" do
|
|
25
|
+
Given {
|
|
26
|
+
@message = any_string
|
|
27
|
+
}
|
|
28
|
+
When {
|
|
29
|
+
@code = lambda { exit_now!(@message) }
|
|
30
|
+
}
|
|
31
|
+
Then {
|
|
32
|
+
exception = assert_raises(Methadone::Error,&@code)
|
|
33
|
+
exception.exit_code.should == 1
|
|
34
|
+
exception.message.should == @message
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
end
|
data/test/test_main.rb
ADDED
|
@@ -0,0 +1,1213 @@
|
|
|
1
|
+
require 'base_test'
|
|
2
|
+
require 'methadone'
|
|
3
|
+
require 'stringio'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
class TestMain < BaseTest
|
|
7
|
+
include Methadone::Main
|
|
8
|
+
|
|
9
|
+
def setup
|
|
10
|
+
@original_argv = ARGV.clone
|
|
11
|
+
ARGV.clear
|
|
12
|
+
@old_stdout = $stdout
|
|
13
|
+
$stdout = StringIO.new
|
|
14
|
+
@logged = StringIO.new
|
|
15
|
+
@custom_logger = Logger.new(@logged)
|
|
16
|
+
|
|
17
|
+
@original_home = ENV['HOME']
|
|
18
|
+
fake_home = '/tmp/fake-home'
|
|
19
|
+
FileUtils.rm_rf(fake_home)
|
|
20
|
+
FileUtils.mkdir(fake_home)
|
|
21
|
+
ENV['HOME'] = fake_home
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Override the built-in logger so we can capture it
|
|
25
|
+
def logger
|
|
26
|
+
@custom_logger
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def teardown
|
|
30
|
+
set_argv @original_argv
|
|
31
|
+
ENV.delete('DEBUG')
|
|
32
|
+
ENV.delete('APP_OPTS')
|
|
33
|
+
$stdout = @old_stdout
|
|
34
|
+
ENV['HOME'] = @original_home
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test_that "my main block gets called by run and has access to CLILogging" do
|
|
38
|
+
Given {
|
|
39
|
+
@called = false
|
|
40
|
+
main do
|
|
41
|
+
begin
|
|
42
|
+
logger.debug "debug"
|
|
43
|
+
logger.info "info"
|
|
44
|
+
logger.warn "warn"
|
|
45
|
+
logger.error "error"
|
|
46
|
+
logger.fatal "fatal"
|
|
47
|
+
@called = true
|
|
48
|
+
rescue => ex
|
|
49
|
+
puts ex.message
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
}
|
|
53
|
+
When run_go_safely
|
|
54
|
+
Then main_shouldve_been_called
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
test_that "my main block does not get command-line parameters that were not specified by args, but they are still available in ARGV" do
|
|
58
|
+
Given {
|
|
59
|
+
@params = []
|
|
60
|
+
@argv = []
|
|
61
|
+
main do |param1,param2,param3|
|
|
62
|
+
@params << param1
|
|
63
|
+
@params << param2
|
|
64
|
+
@params << param3
|
|
65
|
+
@argv = ::ARGV
|
|
66
|
+
end
|
|
67
|
+
set_argv %w(one two three)
|
|
68
|
+
}
|
|
69
|
+
When run_go_safely
|
|
70
|
+
Then {
|
|
71
|
+
@params.should == [nil,nil,nil]
|
|
72
|
+
@argv.should == %w(one two three)
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
test_that "my main block can freely ignore arguments given" do
|
|
77
|
+
Given {
|
|
78
|
+
@called = false
|
|
79
|
+
main do
|
|
80
|
+
@called = true
|
|
81
|
+
end
|
|
82
|
+
set_argv %w(one two three)
|
|
83
|
+
}
|
|
84
|
+
When run_go_safely
|
|
85
|
+
Then main_shouldve_been_called
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
test_that "my main block can ask for arguments that it might not receive" do
|
|
89
|
+
Given {
|
|
90
|
+
@params = []
|
|
91
|
+
@argv = []
|
|
92
|
+
arg 'param1'
|
|
93
|
+
main do |param1,param2,param3|
|
|
94
|
+
@params << param1
|
|
95
|
+
@params << param2
|
|
96
|
+
@params << param3
|
|
97
|
+
@argv = ::ARGV
|
|
98
|
+
end
|
|
99
|
+
set_argv %w(one two)
|
|
100
|
+
}
|
|
101
|
+
When run_go_safely
|
|
102
|
+
Then {
|
|
103
|
+
@params.should == ['one',nil,nil]
|
|
104
|
+
@argv.should == ['two']
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
test_that "go exits zero when main evaluates to nil or some other non number" do
|
|
109
|
+
[nil,'some string',Object.new,[],4.5].each do |non_number|
|
|
110
|
+
Given main_that_exits non_number
|
|
111
|
+
Then {
|
|
112
|
+
assert_exits(0,"for value #{non_number}") { When run_go! }
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
test_that "go exits with the numeric value that main evaluated to" do
|
|
118
|
+
[0,1,2,3].each do |exit_status|
|
|
119
|
+
Given main_that_exits exit_status
|
|
120
|
+
Then {
|
|
121
|
+
assert_exits(exit_status) { When run_go! }
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
test_that "go exits with 70, which is the Linux sysexits.h code for this sort of thing, if there's an exception" do
|
|
127
|
+
Given {
|
|
128
|
+
leak_exceptions false
|
|
129
|
+
main do
|
|
130
|
+
raise "oh noes"
|
|
131
|
+
end
|
|
132
|
+
}
|
|
133
|
+
Then {
|
|
134
|
+
assert_exits(70) { When run_go! }
|
|
135
|
+
assert_logged_at_error "oh noes"
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
test_that "go allows the exception raised to leak through if DEBUG is set in the environment" do
|
|
140
|
+
Given {
|
|
141
|
+
ENV['DEBUG'] = 'true'
|
|
142
|
+
main do
|
|
143
|
+
raise ArgumentError,"oh noes"
|
|
144
|
+
end
|
|
145
|
+
}
|
|
146
|
+
Then {
|
|
147
|
+
assert_raises ArgumentError do
|
|
148
|
+
When run_go!
|
|
149
|
+
end
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
test_that "An exception that's not a StandardError causes the excepteion to break through and raise" do
|
|
154
|
+
Given {
|
|
155
|
+
main do
|
|
156
|
+
raise Exception,"oh noes"
|
|
157
|
+
end
|
|
158
|
+
}
|
|
159
|
+
Then {
|
|
160
|
+
ex = assert_raises Exception do
|
|
161
|
+
When run_go!
|
|
162
|
+
end
|
|
163
|
+
assert_equal "oh noes",ex.message
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
test_that "Non-methadone exceptions leak through if we configure it that way" do
|
|
168
|
+
Given {
|
|
169
|
+
main do
|
|
170
|
+
raise StandardError,"oh noes"
|
|
171
|
+
end
|
|
172
|
+
leak_exceptions true
|
|
173
|
+
}
|
|
174
|
+
Then {
|
|
175
|
+
ex = assert_raises StandardError do
|
|
176
|
+
When run_go!
|
|
177
|
+
end
|
|
178
|
+
assert_equal "oh noes",ex.message
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
test_that "go exits with the exit status included in the special-purpose excepiton" do
|
|
183
|
+
Given {
|
|
184
|
+
main do
|
|
185
|
+
raise Methadone::Error.new(4,"oh noes")
|
|
186
|
+
end
|
|
187
|
+
}
|
|
188
|
+
Then {
|
|
189
|
+
assert_exits(4) { When run_go! }
|
|
190
|
+
assert_logged_at_error "oh noes"
|
|
191
|
+
}
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
test_that "go allows the special methadone exception to leak through if DEBUG is set in the environment" do
|
|
195
|
+
Given {
|
|
196
|
+
ENV['DEBUG'] = 'true'
|
|
197
|
+
main do
|
|
198
|
+
raise Methadone::Error.new(4,"oh noes")
|
|
199
|
+
end
|
|
200
|
+
}
|
|
201
|
+
Then {
|
|
202
|
+
assert_raises Methadone::Error do
|
|
203
|
+
When run_go!
|
|
204
|
+
end
|
|
205
|
+
}
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
test_that "can exit with a specific status by using the helper method instead of making a new exception" do
|
|
209
|
+
Given {
|
|
210
|
+
main do
|
|
211
|
+
exit_now!(4,"oh noes")
|
|
212
|
+
end
|
|
213
|
+
}
|
|
214
|
+
Then {
|
|
215
|
+
assert_exits(4) { When run_go! }
|
|
216
|
+
assert_logged_at_error "oh noes"
|
|
217
|
+
}
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
test_that "when we help_now! we exit and show help" do
|
|
221
|
+
Given {
|
|
222
|
+
@message = any_sentence
|
|
223
|
+
main do
|
|
224
|
+
help_now!(@message)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
opts.on("--switch") { options[:switch] = true }
|
|
228
|
+
opts.on("--flag FLAG") { |value| options[:flag] = value }
|
|
229
|
+
|
|
230
|
+
set_argv []
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
Then {
|
|
234
|
+
assert_exits(64) { When run_go! }
|
|
235
|
+
assert $stdout.string.include?(opts.to_s),"Expected #{$stdout.string} to contain #{opts.to_s}"
|
|
236
|
+
assert_logged_at_error @message
|
|
237
|
+
}
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
test_that "opts allows us to more expediently set up OptionParser" do
|
|
241
|
+
Given {
|
|
242
|
+
@switch = nil
|
|
243
|
+
@flag = nil
|
|
244
|
+
main do
|
|
245
|
+
@switch = options[:switch]
|
|
246
|
+
@flag = options[:flag]
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
opts.on("--switch") { options[:switch] = true }
|
|
250
|
+
opts.on("--flag FLAG") { |value| options[:flag] = value }
|
|
251
|
+
|
|
252
|
+
set_argv %w(--switch --flag value)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
When run_go_safely
|
|
256
|
+
|
|
257
|
+
Then {
|
|
258
|
+
@switch.should be true
|
|
259
|
+
@flag.should == 'value'
|
|
260
|
+
}
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
test_that "when the command line is invalid, we exit with 64 and print the CLI help" do
|
|
264
|
+
Given {
|
|
265
|
+
main do
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
opts.on("--switch") { options[:switch] = true }
|
|
269
|
+
opts.on("--flag FLAG") { |value| options[:flag] = value }
|
|
270
|
+
|
|
271
|
+
set_argv %w(--invalid --flag value)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
Then {
|
|
275
|
+
assert_exits(64) { When run_go! }
|
|
276
|
+
assert $stdout.string.include?(opts.to_s),"Expected #{$stdout.string} to contain #{opts.to_s}"
|
|
277
|
+
}
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
test_that "when setting defaults they get copied to strings/symbols as well" do
|
|
281
|
+
Given {
|
|
282
|
+
@flag_with_string_key_defalt = nil
|
|
283
|
+
@flag_with_symbol_key_defalt = nil
|
|
284
|
+
reset!
|
|
285
|
+
main do
|
|
286
|
+
@flag_with_string_key_defalt = options[:foo]
|
|
287
|
+
@flag_with_symbol_key_defalt = options['bar']
|
|
288
|
+
end
|
|
289
|
+
options['foo'] = 'FOO'
|
|
290
|
+
options[:bar] = 'BAR'
|
|
291
|
+
on("--foo")
|
|
292
|
+
on("--bar")
|
|
293
|
+
}
|
|
294
|
+
When run_go_safely
|
|
295
|
+
Then {
|
|
296
|
+
assert_equal 'FOO',@flag_with_string_key_defalt
|
|
297
|
+
assert_equal 'BAR',@flag_with_symbol_key_defalt
|
|
298
|
+
}
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
test_that "passing non-strings wont' break automagic stuff" do
|
|
302
|
+
Given {
|
|
303
|
+
@foo = nil
|
|
304
|
+
@bar = nil
|
|
305
|
+
main do
|
|
306
|
+
@foo = options[:foo]
|
|
307
|
+
@bar = options[:bar]
|
|
308
|
+
end
|
|
309
|
+
on("--foo ARG",OptionParser::DecimalInteger)
|
|
310
|
+
on("--bar ARG",/^\d/)
|
|
311
|
+
set_argv %w(--foo 88 --bar 4)
|
|
312
|
+
}
|
|
313
|
+
When run_go_safely
|
|
314
|
+
Then {
|
|
315
|
+
assert_equal 88,@foo,@logged.string + $stdout.string
|
|
316
|
+
assert_equal '4',@bar,@logged.string + $stdout.string
|
|
317
|
+
}
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
test_that "omitting the block to opts simply sets the value in the options hash and returns itself" do
|
|
321
|
+
Given {
|
|
322
|
+
@switch = nil
|
|
323
|
+
@negatable = nil
|
|
324
|
+
@flag = nil
|
|
325
|
+
@f = nil
|
|
326
|
+
@other = nil
|
|
327
|
+
@some_other = nil
|
|
328
|
+
@with_dashes = nil
|
|
329
|
+
main do
|
|
330
|
+
@switch = [options[:switch],options['switch']]
|
|
331
|
+
@flag = [options[:flag],options['flag']]
|
|
332
|
+
@f = [options[:f],options['f']]
|
|
333
|
+
@negatable = [options[:negatable],options['negatable']]
|
|
334
|
+
@other = [options[:other],options['other']]
|
|
335
|
+
@some_other = [options[:some_other],options['some_other']]
|
|
336
|
+
@with_dashes = [options[:'flag-with-dashes'],options['flag-with-dashes']]
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
on("--switch")
|
|
340
|
+
on("--[no-]negatable")
|
|
341
|
+
on("--flag FLAG","-f","Some documentation string")
|
|
342
|
+
on("--flag-with-dashes FOO")
|
|
343
|
+
on("--other") do
|
|
344
|
+
options[:some_other] = true
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
set_argv %w(--switch --flag value --negatable --other --flag-with-dashes=BAR)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
When run_go_safely
|
|
351
|
+
|
|
352
|
+
Then {
|
|
353
|
+
@switch[0].should be true
|
|
354
|
+
@some_other[0].should be true
|
|
355
|
+
@other[0].should_not be true
|
|
356
|
+
@flag[0].should == 'value'
|
|
357
|
+
@f[0].should == 'value'
|
|
358
|
+
@with_dashes[0].should == 'BAR'
|
|
359
|
+
|
|
360
|
+
@switch[1].should be true
|
|
361
|
+
@some_other[1].should be nil # ** this is set manually
|
|
362
|
+
@other[1].should_not be true
|
|
363
|
+
@flag[1].should == 'value'
|
|
364
|
+
@f[1].should == 'value'
|
|
365
|
+
@with_dashes[1].should == 'BAR'
|
|
366
|
+
|
|
367
|
+
opts.to_s.should match /Some documentation string/
|
|
368
|
+
}
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
test_that "without specifying options, options in brackets doesn't show up in our banner" do
|
|
372
|
+
Given {
|
|
373
|
+
main {}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
Then {
|
|
377
|
+
opts.banner.should_not match /\[options\]/
|
|
378
|
+
}
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
test_that "when specifying an option, [options] shows up in the banner" do
|
|
382
|
+
Given {
|
|
383
|
+
main {}
|
|
384
|
+
on("-s")
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
Then {
|
|
388
|
+
opts.banner.should match /\[options\]/
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
test_that "I can specify which arguments my app takes and if they are required as well as document them" do
|
|
394
|
+
Given {
|
|
395
|
+
main {}
|
|
396
|
+
@db_name_desc = any_string
|
|
397
|
+
@user_desc = any_string
|
|
398
|
+
@password_desc = any_string
|
|
399
|
+
|
|
400
|
+
arg :db_name, @db_name_desc
|
|
401
|
+
arg :user, :required, @user_desc
|
|
402
|
+
arg :password, :optional, @password_desc
|
|
403
|
+
}
|
|
404
|
+
When run_go_safely
|
|
405
|
+
Then {
|
|
406
|
+
opts.banner.should match /db_name user \[password\]$/
|
|
407
|
+
opts.to_s.should match /#{@db_name_desc}/
|
|
408
|
+
opts.to_s.should match /#{@user_desc}/
|
|
409
|
+
opts.to_s.should match /#{@password_desc}/
|
|
410
|
+
}
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
test_that "I can specify which arguments my app takes and if they are singular or plural" do
|
|
414
|
+
Given {
|
|
415
|
+
main {}
|
|
416
|
+
|
|
417
|
+
arg :db_name
|
|
418
|
+
arg :user, :required, :one
|
|
419
|
+
arg :tables, :many
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
Then {
|
|
423
|
+
opts.banner.should match /db_name user tables...$/
|
|
424
|
+
}
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
test_that "I can specify which arguments my app takes and if they are singular or optional plural" do
|
|
428
|
+
Given {
|
|
429
|
+
main {}
|
|
430
|
+
|
|
431
|
+
arg :db_name
|
|
432
|
+
arg :user, :required, :one
|
|
433
|
+
arg :tables, :any
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
Then {
|
|
437
|
+
opts.banner.should match /db_name user \[tables...\]$/
|
|
438
|
+
}
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
test_that "I can set a description for my app" do
|
|
442
|
+
Given {
|
|
443
|
+
main {}
|
|
444
|
+
description "An app of total awesome"
|
|
445
|
+
|
|
446
|
+
}
|
|
447
|
+
Then {
|
|
448
|
+
opts.banner.should match /^An app of total awesome$/
|
|
449
|
+
}
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
test_that "when I override the banner, we don't automatically do anything" do
|
|
453
|
+
Given {
|
|
454
|
+
main {}
|
|
455
|
+
opts.banner = "FOOBAR"
|
|
456
|
+
|
|
457
|
+
on("-s")
|
|
458
|
+
}
|
|
459
|
+
When {opts}
|
|
460
|
+
Then {
|
|
461
|
+
opts.banner.should == 'FOOBAR'
|
|
462
|
+
}
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
test_that "when I say an argument is required and its omitted, I get an error" do
|
|
466
|
+
Given {
|
|
467
|
+
main {}
|
|
468
|
+
arg :foo
|
|
469
|
+
arg :bar
|
|
470
|
+
|
|
471
|
+
set_argv %w(blah)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
Then {
|
|
475
|
+
assert_exits(64) { When run_go! }
|
|
476
|
+
assert_logged_at_error("parse error: 'bar' is required")
|
|
477
|
+
}
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
test_that "when I say an argument is many and its omitted, I get an error" do
|
|
481
|
+
Given {
|
|
482
|
+
main {}
|
|
483
|
+
arg :foo
|
|
484
|
+
arg :bar, :many
|
|
485
|
+
|
|
486
|
+
set_argv %w(blah)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
Then {
|
|
490
|
+
assert_exits(64) { When run_go! }
|
|
491
|
+
assert_logged_at_error("parse error: at least one 'bar' is required")
|
|
492
|
+
}
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
test_that "when I specify a version, it shows up in the banner" do
|
|
496
|
+
Given {
|
|
497
|
+
main{}
|
|
498
|
+
version "0.0.1"
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
Then {
|
|
502
|
+
opts.banner.should match /^v0.0.1/m
|
|
503
|
+
}
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
test_that "when I specify a version, I can get help via --version" do
|
|
507
|
+
Given {
|
|
508
|
+
main{}
|
|
509
|
+
version "0.0.1"
|
|
510
|
+
set_argv(['--version'])
|
|
511
|
+
}
|
|
512
|
+
Then run_go_safely
|
|
513
|
+
And {
|
|
514
|
+
opts.to_s.should match /Show help\/version info/m
|
|
515
|
+
$stdout.string.should match /^#{@version}$/
|
|
516
|
+
}
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
test_that "when I specify a version with custom help, it shows up" do
|
|
520
|
+
@version_message = "SHOW ME VERSIONS"
|
|
521
|
+
Given {
|
|
522
|
+
main{}
|
|
523
|
+
version "0.0.1",@version_message
|
|
524
|
+
set_argv(['--verison'])
|
|
525
|
+
}
|
|
526
|
+
Then run_go_safely
|
|
527
|
+
And {
|
|
528
|
+
opts.to_s.should match /#{@version_message}/
|
|
529
|
+
}
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
test_that "when I specify a version with :basic format, only the command and version show up and the help is 'show version info'" do
|
|
533
|
+
@version = "2.0.9.pre"
|
|
534
|
+
Given {
|
|
535
|
+
version @version, :basic
|
|
536
|
+
set_argv %w(--version)
|
|
537
|
+
}
|
|
538
|
+
When run_go_safely
|
|
539
|
+
Then {
|
|
540
|
+
opts.to_s.should match /^ *--version.*Show version info$/
|
|
541
|
+
$stdout.string.should match /^#{::File.basename($0)} version #{@version}$/
|
|
542
|
+
}
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
test_that "when I specify a version with :terse format, only the version show up and the help is 'show version'" do
|
|
546
|
+
@version = "2.0.9.pre"
|
|
547
|
+
Given {
|
|
548
|
+
version @version, :terse
|
|
549
|
+
set_argv %w(--version)
|
|
550
|
+
}
|
|
551
|
+
When run_go_safely
|
|
552
|
+
Then {
|
|
553
|
+
opts.to_s.should match /^ *--version.*Show version$/
|
|
554
|
+
$stdout.string.should match /^#{@version}$/
|
|
555
|
+
}
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
test_that "default values for boolean options are put into the docstring" do
|
|
559
|
+
Given {
|
|
560
|
+
main {}
|
|
561
|
+
options[:foo] = false
|
|
562
|
+
options[:bar] = true
|
|
563
|
+
on("--foo","Do the foo")
|
|
564
|
+
on("--[no-]bar", "Bar it like crazy")
|
|
565
|
+
}
|
|
566
|
+
When {
|
|
567
|
+
@help_string = opts.to_s
|
|
568
|
+
}
|
|
569
|
+
When {
|
|
570
|
+
@help_string.should match /--foo.*\n.*\(default: false\)/
|
|
571
|
+
@help_string.should match /--\[no-\]bar.*\n.*\(default: true\)/
|
|
572
|
+
}
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
test_that "default values for options are put into the docstring" do
|
|
576
|
+
Given {
|
|
577
|
+
main {}
|
|
578
|
+
options[:foo] = "bar"
|
|
579
|
+
on("--foo ARG","Indicate the type of foo")
|
|
580
|
+
}
|
|
581
|
+
When {
|
|
582
|
+
@help_string = opts.to_s
|
|
583
|
+
}
|
|
584
|
+
When {
|
|
585
|
+
@help_string.should match /\(default: bar\)/
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
test_that "default values for options with several names are put into the docstring" do
|
|
591
|
+
Given {
|
|
592
|
+
main {}
|
|
593
|
+
options[:foo] = "bar"
|
|
594
|
+
on("-f ARG","--foo","Indicate the type of foo")
|
|
595
|
+
}
|
|
596
|
+
When {
|
|
597
|
+
@help_string = opts.to_s
|
|
598
|
+
}
|
|
599
|
+
When {
|
|
600
|
+
@help_string.should match /\(default: bar\)/
|
|
601
|
+
}
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
test_that "when getting defaults from an environment variable, show it in the help output" do
|
|
605
|
+
Given app_to_use_environment
|
|
606
|
+
When run_go_safely
|
|
607
|
+
And {
|
|
608
|
+
@help_string = opts.to_s
|
|
609
|
+
}
|
|
610
|
+
Then {
|
|
611
|
+
@help_string.should match /Default values can be placed in the APP_OPTS environment variable/
|
|
612
|
+
}
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
test_that "when we want to get opts from the environment, we can" do
|
|
616
|
+
Given app_to_use_environment
|
|
617
|
+
And {
|
|
618
|
+
@flag_value = '56'
|
|
619
|
+
@some_arg = any_string
|
|
620
|
+
set_argv([])
|
|
621
|
+
ENV['APP_OPTS'] = "--switch --flag=#{@flag_value} #{@some_arg}"
|
|
622
|
+
}
|
|
623
|
+
When {
|
|
624
|
+
@code = lambda { go! }
|
|
625
|
+
}
|
|
626
|
+
Then {
|
|
627
|
+
assert_exits(0,'',&@code)
|
|
628
|
+
@switch.should == true
|
|
629
|
+
@flag.should == @flag_value
|
|
630
|
+
@args.should == [@some_arg]
|
|
631
|
+
}
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
test_that "environment args are overridden by the command line" do
|
|
635
|
+
Given app_to_use_environment
|
|
636
|
+
And {
|
|
637
|
+
@flag_value = any_string
|
|
638
|
+
ENV['APP_OPTS'] = "--switch --flag=#{any_string}"
|
|
639
|
+
set_argv(['--flag',@flag_value])
|
|
640
|
+
}
|
|
641
|
+
When {
|
|
642
|
+
@code = lambda { go! }
|
|
643
|
+
}
|
|
644
|
+
Then {
|
|
645
|
+
assert_exits(0,'',&@code)
|
|
646
|
+
@switch.should == true
|
|
647
|
+
@flag.should == @flag_value
|
|
648
|
+
}
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
test_that "environment args correctly handle spaces" do
|
|
652
|
+
Given app_to_use_environment
|
|
653
|
+
And {
|
|
654
|
+
@flag_value = any_string + ' ' + any_string
|
|
655
|
+
ENV['APP_OPTS'] = "--switch --flag='#{@flag_value}'"
|
|
656
|
+
}
|
|
657
|
+
When {
|
|
658
|
+
@code = lambda { go! }
|
|
659
|
+
}
|
|
660
|
+
Then {
|
|
661
|
+
assert_exits(0,'',&@code)
|
|
662
|
+
@switch.should == true
|
|
663
|
+
@flag.should == @flag_value
|
|
664
|
+
}
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
test_that "environment args correctly handle spaces via backslash stuff" do
|
|
668
|
+
Given app_to_use_environment
|
|
669
|
+
And {
|
|
670
|
+
cli_flag_value = any_string(:max => 4) + "\\ " + any_string(:max => 4)
|
|
671
|
+
@flag_value = cli_flag_value.gsub("\\ "," ")
|
|
672
|
+
ENV['APP_OPTS'] = "--switch --flag=#{cli_flag_value}"
|
|
673
|
+
}
|
|
674
|
+
When {
|
|
675
|
+
@code = lambda { go! }
|
|
676
|
+
}
|
|
677
|
+
Then {
|
|
678
|
+
assert_exits(0,'',&@code)
|
|
679
|
+
@switch.should == true
|
|
680
|
+
@flag.should == @flag_value
|
|
681
|
+
}
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
test_that "we can get defaults from a YAML config file if it's specified" do
|
|
685
|
+
Given app_to_use_rc_file
|
|
686
|
+
And {
|
|
687
|
+
@flag_value = any_string
|
|
688
|
+
rc_file = File.join(ENV['HOME'],'.my_app.rc')
|
|
689
|
+
File.open(rc_file,'w') do |file|
|
|
690
|
+
file.puts({
|
|
691
|
+
'switch' => true,
|
|
692
|
+
'flag' => @flag_value,
|
|
693
|
+
}.to_yaml)
|
|
694
|
+
end
|
|
695
|
+
}
|
|
696
|
+
When {
|
|
697
|
+
@code = lambda { go! }
|
|
698
|
+
}
|
|
699
|
+
Then {
|
|
700
|
+
assert_exits(0,&@code)
|
|
701
|
+
@switch.should == true
|
|
702
|
+
@flag.should == @flag_value
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
test_that "we can get defaults from an absolute config filename" do
|
|
708
|
+
tempfile = Tempfile.new('methadone_test.rc')
|
|
709
|
+
Given app_to_use_rc_file(tempfile.path)
|
|
710
|
+
And {
|
|
711
|
+
@flag_value = any_string
|
|
712
|
+
rc_file = File.join(tempfile.path)
|
|
713
|
+
File.open(rc_file,'w') do |file|
|
|
714
|
+
file.puts({
|
|
715
|
+
'switch' => true,
|
|
716
|
+
'flag' => @flag_value,
|
|
717
|
+
}.to_yaml)
|
|
718
|
+
end
|
|
719
|
+
}
|
|
720
|
+
When {
|
|
721
|
+
@code = lambda { go! }
|
|
722
|
+
}
|
|
723
|
+
Then {
|
|
724
|
+
assert_exits(0,&@code)
|
|
725
|
+
@switch.should == true
|
|
726
|
+
@flag.should == @flag_value
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
test_that "we can specify an rc file even if it doesn't exist" do
|
|
733
|
+
Given app_to_use_rc_file
|
|
734
|
+
And {
|
|
735
|
+
@flag_value = any_string
|
|
736
|
+
rc_file = File.join(ENV['HOME'],'.my_app.rc')
|
|
737
|
+
raise "Something's wrong, expection rc file not to exist" if File.exists?(rc_file)
|
|
738
|
+
}
|
|
739
|
+
When {
|
|
740
|
+
@code = lambda { go! }
|
|
741
|
+
}
|
|
742
|
+
Then {
|
|
743
|
+
assert_exits(0,&@code)
|
|
744
|
+
@switch.should == nil
|
|
745
|
+
@flag.should == nil
|
|
746
|
+
}
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
test_that "we can use a simpler, text format for the rc file" do
|
|
750
|
+
Given app_to_use_rc_file
|
|
751
|
+
And {
|
|
752
|
+
@flag_value = any_string
|
|
753
|
+
rc_file = File.join(ENV['HOME'],'.my_app.rc')
|
|
754
|
+
File.open(rc_file,'w') do |file|
|
|
755
|
+
file.puts "--switch --flag=#{@flag_value}"
|
|
756
|
+
end
|
|
757
|
+
}
|
|
758
|
+
When {
|
|
759
|
+
@code = lambda { go! }
|
|
760
|
+
}
|
|
761
|
+
Then {
|
|
762
|
+
assert_exits(0,&@code)
|
|
763
|
+
@switch.should == true
|
|
764
|
+
@flag.should == @flag_value
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
test_that "the text format for the rc file attempts to respect quoted arguments" do
|
|
770
|
+
Given app_to_use_rc_file
|
|
771
|
+
And {
|
|
772
|
+
@flag_value = any_string(:max => 10) + " " + any_string(:max => 10)
|
|
773
|
+
rc_file = File.join(ENV['HOME'],'.my_app.rc')
|
|
774
|
+
File.open(rc_file,'w') do |file|
|
|
775
|
+
file.puts "--switch --flag='#{@flag_value}'"
|
|
776
|
+
end
|
|
777
|
+
}
|
|
778
|
+
When {
|
|
779
|
+
@code = lambda { go! }
|
|
780
|
+
}
|
|
781
|
+
Then {
|
|
782
|
+
assert_exits(0,&@code)
|
|
783
|
+
@switch.should == true
|
|
784
|
+
@flag.should == @flag_value
|
|
785
|
+
}
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
test_that "with an ill-formed rc file, we get a reasonable error message" do
|
|
789
|
+
Given app_to_use_rc_file
|
|
790
|
+
And {
|
|
791
|
+
@flag_value = any_string
|
|
792
|
+
rc_file = File.join(ENV['HOME'],'.my_app.rc')
|
|
793
|
+
File.open(rc_file,'w') do |file|
|
|
794
|
+
file.puts OpenStruct.new(:foo => :bar).to_yaml
|
|
795
|
+
end
|
|
796
|
+
}
|
|
797
|
+
When {
|
|
798
|
+
@code = lambda { go! }
|
|
799
|
+
}
|
|
800
|
+
Then {
|
|
801
|
+
assert_exits(64,&@code)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
test_that "we can call methods prior to calling main without a problem" do
|
|
807
|
+
Given {
|
|
808
|
+
description "An app of total awesome"
|
|
809
|
+
opts.on("--switch") { options[:switch] = true }
|
|
810
|
+
main {}
|
|
811
|
+
}
|
|
812
|
+
Then {
|
|
813
|
+
opts.banner.should match /^An app of total awesome$/
|
|
814
|
+
opts.to_s.should match /--switch/
|
|
815
|
+
}
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
test_that "usage is displayed if called with no arguments given when help_if_bare specified" do
|
|
819
|
+
Given {
|
|
820
|
+
help_if_bare
|
|
821
|
+
on("--required VALUE")
|
|
822
|
+
main {puts 'main called'}
|
|
823
|
+
}
|
|
824
|
+
When {
|
|
825
|
+
@code = lambda {go!}
|
|
826
|
+
}
|
|
827
|
+
Then {
|
|
828
|
+
assert_exits(64,&@code)
|
|
829
|
+
$stdout.string.should_not match /main called/
|
|
830
|
+
$stdout.string.should match /Usage:.*--required VALUE/m
|
|
831
|
+
}
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
test_that "arguments are filled according to their need" do
|
|
835
|
+
Given {
|
|
836
|
+
@can_use_one = nil
|
|
837
|
+
@any_will_do = nil
|
|
838
|
+
@need_1 = nil
|
|
839
|
+
@at_least_one = nil
|
|
840
|
+
@if_youve_got_one = nil
|
|
841
|
+
@any_left = nil
|
|
842
|
+
@last_one = nil
|
|
843
|
+
arg 'can_use_one', :optional, Integer
|
|
844
|
+
arg 'any_will_do', :any
|
|
845
|
+
arg 'need_1', :required
|
|
846
|
+
arg 'at_least_one', :many
|
|
847
|
+
arg 'if_youve_got_one', :optional
|
|
848
|
+
arg 'any_left', :any
|
|
849
|
+
arg 'last_one', :required
|
|
850
|
+
main do |can_use_one,any_will_do,need_1,at_least_one,if_youve_got_one,any_left,last_one|
|
|
851
|
+
@can_use_one = can_use_one
|
|
852
|
+
@any_will_do = any_will_do
|
|
853
|
+
@need_1 = need_1
|
|
854
|
+
@at_least_one = at_least_one
|
|
855
|
+
@if_youve_got_one = if_youve_got_one
|
|
856
|
+
@any_left = any_left
|
|
857
|
+
@last_one = last_one
|
|
858
|
+
end
|
|
859
|
+
set_argv %w(1 2 3 4 5 6 7 8 9 10)
|
|
860
|
+
}
|
|
861
|
+
When run_go_safely
|
|
862
|
+
Then {
|
|
863
|
+
@can_use_one.should == '1'
|
|
864
|
+
@any_will_do.should == %w(2 3 4 5 6 7)
|
|
865
|
+
@need_1.should == '8'
|
|
866
|
+
@at_least_one.should == ['9']
|
|
867
|
+
@if_youve_got_one.should == nil
|
|
868
|
+
@any_left.should == []
|
|
869
|
+
@last_one.should == '10'
|
|
870
|
+
}
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
test_that "arguments can be given valid values" do
|
|
874
|
+
Given {
|
|
875
|
+
arg "foo", %w(one two three)
|
|
876
|
+
@foo = nil
|
|
877
|
+
main do |foo|
|
|
878
|
+
@foo = foo
|
|
879
|
+
end
|
|
880
|
+
set_argv %w(two)
|
|
881
|
+
}
|
|
882
|
+
When run_go_safely
|
|
883
|
+
Then {
|
|
884
|
+
@foo = 'two'
|
|
885
|
+
}
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
test_that "arguments can be given valid values, and raise errors when they don't match" do
|
|
889
|
+
Given {
|
|
890
|
+
arg "foo", %w(one two three)
|
|
891
|
+
@foo = nil
|
|
892
|
+
main do |foo|
|
|
893
|
+
@foo = foo
|
|
894
|
+
end
|
|
895
|
+
set_argv %w(four)
|
|
896
|
+
}
|
|
897
|
+
When run_go_safely
|
|
898
|
+
Then {
|
|
899
|
+
assert_logged_at_error("parse error: foo: 'four' is invalid")
|
|
900
|
+
@foo = nil
|
|
901
|
+
}
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
test_that "arguments that take multiple values can be given valid values" do
|
|
905
|
+
Given {
|
|
906
|
+
arg "foo", :many, %w(one two three)
|
|
907
|
+
@foo = nil
|
|
908
|
+
main do |foo|
|
|
909
|
+
@foo = foo
|
|
910
|
+
end
|
|
911
|
+
set_argv %w(two one two)
|
|
912
|
+
}
|
|
913
|
+
When run_go_safely
|
|
914
|
+
Then {
|
|
915
|
+
@foo = %w(two one two)
|
|
916
|
+
}
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
test_that "arguments that take multiple values can be given valid values, and raise errors when they don't match" do
|
|
920
|
+
Given {
|
|
921
|
+
arg "foo", :many, %w(one two three)
|
|
922
|
+
@foo = nil
|
|
923
|
+
main do |foo|
|
|
924
|
+
@foo = foo
|
|
925
|
+
end
|
|
926
|
+
set_argv %w(four one two seven)
|
|
927
|
+
}
|
|
928
|
+
When run_go_safely
|
|
929
|
+
Then {
|
|
930
|
+
assert_logged_at_error("parse error: foo: The following value(s) were invalid: 'four seven'")
|
|
931
|
+
@foo = nil
|
|
932
|
+
}
|
|
933
|
+
end
|
|
934
|
+
test_that "arguments can be given regexp filters" do
|
|
935
|
+
Given {
|
|
936
|
+
arg "foo", /^th/
|
|
937
|
+
@foo = nil
|
|
938
|
+
main do |foo|
|
|
939
|
+
@foo = foo
|
|
940
|
+
end
|
|
941
|
+
set_argv %w(this)
|
|
942
|
+
}
|
|
943
|
+
When run_go_safely
|
|
944
|
+
Then {
|
|
945
|
+
@foo = 'this'
|
|
946
|
+
}
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
test_that "arguments can be given regexp filters, and raise errors when they don't match" do
|
|
950
|
+
Given {
|
|
951
|
+
arg "foo", :optional, /^th/
|
|
952
|
+
@foo = nil
|
|
953
|
+
main do |foo|
|
|
954
|
+
@foo = foo
|
|
955
|
+
end
|
|
956
|
+
set_argv %w(width)
|
|
957
|
+
}
|
|
958
|
+
When run_go_safely
|
|
959
|
+
Then {
|
|
960
|
+
assert_logged_at_error("parse error: foo: 'width' is invalid")
|
|
961
|
+
@foo = nil
|
|
962
|
+
}
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
test_that "arguments that take multiple values can be given regexp filters" do
|
|
966
|
+
Given {
|
|
967
|
+
arg "foo", :many, /^th/
|
|
968
|
+
@foo = nil
|
|
969
|
+
main do |foo|
|
|
970
|
+
@foo = foo
|
|
971
|
+
end
|
|
972
|
+
set_argv %w(this that the\ other)
|
|
973
|
+
}
|
|
974
|
+
When run_go_safely
|
|
975
|
+
Then {
|
|
976
|
+
@foo = %w(this that the\ other)
|
|
977
|
+
}
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
test_that "arguments that take multiple values can be given regexp filters, and raise errors when they don't match" do
|
|
981
|
+
Given {
|
|
982
|
+
arg "foo", :any, /^th/
|
|
983
|
+
@foo = nil
|
|
984
|
+
main do |foo|
|
|
985
|
+
@foo = foo
|
|
986
|
+
end
|
|
987
|
+
set_argv %w(there is this theory on things that grow)
|
|
988
|
+
}
|
|
989
|
+
When run_go_safely
|
|
990
|
+
Then {
|
|
991
|
+
assert_logged_at_error("parse error: foo: The following value(s) were invalid: 'is on grow'")
|
|
992
|
+
@foo = nil
|
|
993
|
+
}
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
test_that "arguments can be given multiple filters, requiring only one be accepted" do
|
|
997
|
+
Given {
|
|
998
|
+
arg "foo", :any, /^....$/, ['one', 'two', 'six'], /\A..?e.?e.?\z/
|
|
999
|
+
@foo = nil
|
|
1000
|
+
main do |foo|
|
|
1001
|
+
@foo = foo
|
|
1002
|
+
end
|
|
1003
|
+
set_argv %w(one two three four five six seven)
|
|
1004
|
+
}
|
|
1005
|
+
When run_go_safely
|
|
1006
|
+
Then {
|
|
1007
|
+
@foo = %w(one two three four five six seven)
|
|
1008
|
+
}
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
test_that "options can be mutually exclusive" do
|
|
1012
|
+
Given {
|
|
1013
|
+
@first = nil
|
|
1014
|
+
@second = nil
|
|
1015
|
+
reset!
|
|
1016
|
+
main do
|
|
1017
|
+
@first = options[:f]
|
|
1018
|
+
@second = options[:s]
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
on("-f", "--first", "First Option")
|
|
1022
|
+
on("-s", "Second Option", :excludes => :f)
|
|
1023
|
+
}
|
|
1024
|
+
When {
|
|
1025
|
+
set_argv %w(-f)
|
|
1026
|
+
@code = lambda { go! }
|
|
1027
|
+
}
|
|
1028
|
+
Then {
|
|
1029
|
+
assert_exits(0,&@code)
|
|
1030
|
+
@first.should be_truthy
|
|
1031
|
+
@second.should be_nil
|
|
1032
|
+
}
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
test_that "options can be mutually exclusive, which raise an error if both are used" do
|
|
1036
|
+
Given {
|
|
1037
|
+
|
|
1038
|
+
@first = nil
|
|
1039
|
+
@second = nil
|
|
1040
|
+
reset!
|
|
1041
|
+
main do
|
|
1042
|
+
@first = options[:f]
|
|
1043
|
+
@second = options[:s]
|
|
1044
|
+
end
|
|
1045
|
+
on("-f", "--first", "First Option")
|
|
1046
|
+
on("-s", "Second Option", :excludes => :f)
|
|
1047
|
+
}
|
|
1048
|
+
When {
|
|
1049
|
+
set_argv %w(-f -s)
|
|
1050
|
+
@code = lambda { go! }
|
|
1051
|
+
}
|
|
1052
|
+
Then {
|
|
1053
|
+
assert_exits(64,&@code)
|
|
1054
|
+
assert_logged_at_error("parse error: -s cannot be used if already using -f|--first")
|
|
1055
|
+
$stdout.string.should match /Usage:/
|
|
1056
|
+
}
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
test_that "options can be mutually exclusive, which raise an error if both are used - order doesn't matter" do
|
|
1060
|
+
Given {
|
|
1061
|
+
|
|
1062
|
+
@first = nil
|
|
1063
|
+
@second = nil
|
|
1064
|
+
reset!
|
|
1065
|
+
main do
|
|
1066
|
+
@first = options[:f]
|
|
1067
|
+
@second = options[:s]
|
|
1068
|
+
end
|
|
1069
|
+
on("-f", "--first", "First Option")
|
|
1070
|
+
on("-s", "Second Option", :excludes => :f)
|
|
1071
|
+
}
|
|
1072
|
+
When {
|
|
1073
|
+
set_argv %w(-s -f)
|
|
1074
|
+
@code = lambda { go! }
|
|
1075
|
+
}
|
|
1076
|
+
Then {
|
|
1077
|
+
assert_exits(64,&@code)
|
|
1078
|
+
assert_logged_at_error("parse error: -s cannot be used if already using -f|--first")
|
|
1079
|
+
$stdout.string.should match /Usage:/
|
|
1080
|
+
}
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
test_that "options can be mutually exclusive, the enemy of my enemy is my friend" do
|
|
1084
|
+
Given {
|
|
1085
|
+
|
|
1086
|
+
@first = nil
|
|
1087
|
+
@second = nil
|
|
1088
|
+
@third = nil
|
|
1089
|
+
reset!
|
|
1090
|
+
main do
|
|
1091
|
+
@first = options[:f]
|
|
1092
|
+
@second = options[:s]
|
|
1093
|
+
@third = options[:third]
|
|
1094
|
+
end
|
|
1095
|
+
on("-f", "--first", "First Option")
|
|
1096
|
+
on("--another-one", "Second Option", :excludes => :f)
|
|
1097
|
+
on("--third TEST", "Second Option", :excludes => "another-one")
|
|
1098
|
+
}
|
|
1099
|
+
When {
|
|
1100
|
+
set_argv %w(-f --third value)
|
|
1101
|
+
@code = lambda { go! }
|
|
1102
|
+
}
|
|
1103
|
+
Then {
|
|
1104
|
+
assert_exits(0,&@code)
|
|
1105
|
+
@first.should be_truthy
|
|
1106
|
+
@second.should be_nil
|
|
1107
|
+
@third.should == 'value'
|
|
1108
|
+
}
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
test_that "options can be options can require other options to be present" do
|
|
1112
|
+
Given {
|
|
1113
|
+
|
|
1114
|
+
@first = nil
|
|
1115
|
+
@second = nil
|
|
1116
|
+
@third = nil
|
|
1117
|
+
reset!
|
|
1118
|
+
main do
|
|
1119
|
+
@first = options[:f]
|
|
1120
|
+
@second = options[:s]
|
|
1121
|
+
@third = options[:third]
|
|
1122
|
+
end
|
|
1123
|
+
on("-f", "--first", "First Option")
|
|
1124
|
+
on("-a","--another-one", "Second Option")
|
|
1125
|
+
on("--third TEST", "Second Option", :requires => [:first,'another-one'])
|
|
1126
|
+
}
|
|
1127
|
+
When {
|
|
1128
|
+
set_argv %w(-f --third value)
|
|
1129
|
+
@code = lambda { go! }
|
|
1130
|
+
}
|
|
1131
|
+
Then {
|
|
1132
|
+
assert_exits(64,&@code)
|
|
1133
|
+
assert_logged_at_error("parse error: Missing option -a|--another-one required by option --third TEST")
|
|
1134
|
+
$stdout.string.should match /Usage:/
|
|
1135
|
+
}
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
private
|
|
1139
|
+
|
|
1140
|
+
def app_to_use_rc_file(rc_file = '.my_app.rc')
|
|
1141
|
+
lambda {
|
|
1142
|
+
reset!
|
|
1143
|
+
@switch = nil
|
|
1144
|
+
@flag = nil
|
|
1145
|
+
@args = nil
|
|
1146
|
+
main do |*args|
|
|
1147
|
+
@switch = options[:switch]
|
|
1148
|
+
@flag = options[:flag]
|
|
1149
|
+
@args = args
|
|
1150
|
+
end
|
|
1151
|
+
|
|
1152
|
+
defaults_from_config_file rc_file
|
|
1153
|
+
|
|
1154
|
+
on('--switch','Some Switch')
|
|
1155
|
+
on('--flag FOO','Some Flag')
|
|
1156
|
+
}
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
def main_that_exits(exit_status)
|
|
1160
|
+
proc { main { exit_status } }
|
|
1161
|
+
end
|
|
1162
|
+
|
|
1163
|
+
def app_to_use_environment
|
|
1164
|
+
lambda {
|
|
1165
|
+
@switch = nil
|
|
1166
|
+
@flag = nil
|
|
1167
|
+
@args = nil
|
|
1168
|
+
arg :args, :any
|
|
1169
|
+
main do |args|
|
|
1170
|
+
@switch = options[:switch]
|
|
1171
|
+
@flag = options[:flag]
|
|
1172
|
+
@args = args
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
defaults_from_env_var 'APP_OPTS'
|
|
1176
|
+
|
|
1177
|
+
on('--switch','Some Switch')
|
|
1178
|
+
on('--flag FOO','Some Flag')
|
|
1179
|
+
}
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
def main_shouldve_been_called
|
|
1183
|
+
Proc.new { assert @called,"Main block wasn't called?!" }
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
def run_go_safely
|
|
1187
|
+
Proc.new { safe_go! }
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
# Calls go!, but traps the exit
|
|
1191
|
+
def safe_go!
|
|
1192
|
+
go!
|
|
1193
|
+
rescue SystemExit
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
def run_go!; proc { go! }; end
|
|
1197
|
+
|
|
1198
|
+
def assert_logged_at_error(expected_message)
|
|
1199
|
+
@logged.string.should include expected_message
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
def assert_exits(exit_code,message='',&block)
|
|
1203
|
+
block.call
|
|
1204
|
+
fail "Expected an exit of #{exit_code}, but we didn't even exit!"
|
|
1205
|
+
rescue SystemExit => ex
|
|
1206
|
+
assert_equal exit_code,ex.status,@logged.string
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
def set_argv(args)
|
|
1210
|
+
ARGV.clear
|
|
1211
|
+
args.each { |arg| ARGV << arg }
|
|
1212
|
+
end
|
|
1213
|
+
end
|