benry-cmdapp 0.1.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 +7 -0
- data/CHANGES.md +8 -0
- data/MIT-LICENSE +21 -0
- data/README.md +2475 -0
- data/benry-cmdapp.gemspec +38 -0
- data/doc/benry-cmdapp.html +2314 -0
- data/doc/css/style.css +168 -0
- data/lib/benry/cmdapp.rb +1376 -0
- data/test/action_test.rb +1038 -0
- data/test/app_test.rb +1371 -0
- data/test/func_test.rb +137 -0
- data/test/help_test.rb +755 -0
- data/test/index_test.rb +185 -0
- data/test/run_all.rb +7 -0
- data/test/shared.rb +75 -0
- data/test/util_test.rb +189 -0
- metadata +98 -0
data/test/app_test.rb
ADDED
@@ -0,0 +1,1371 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'oktest'
|
4
|
+
|
5
|
+
require 'benry/cmdapp'
|
6
|
+
require_relative './shared'
|
7
|
+
|
8
|
+
|
9
|
+
Oktest.scope do
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
topic Benry::CmdApp::Config do
|
14
|
+
|
15
|
+
|
16
|
+
topic '#initialize()' do
|
17
|
+
|
18
|
+
spec "[!uve4e] sets command name automatically if not provided." do
|
19
|
+
config = Benry::CmdApp::Config.new("test")
|
20
|
+
ok {config.app_command} != nil
|
21
|
+
ok {config.app_command} == File.basename($0)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
topic Benry::CmdApp::AppOptionSchema do
|
31
|
+
|
32
|
+
|
33
|
+
topic '#initialize()' do
|
34
|
+
|
35
|
+
def new_gschema(desc="", version=nil, **kwargs)
|
36
|
+
config = Benry::CmdApp::Config.new(desc, version, **kwargs)
|
37
|
+
x = Benry::CmdApp::AppOptionSchema.new(config)
|
38
|
+
return x
|
39
|
+
end
|
40
|
+
|
41
|
+
spec "[!3ihzx] do nothing when config is nil." do
|
42
|
+
x = nil
|
43
|
+
pr = proc { x = Benry::CmdApp::AppOptionSchema.new(nil) }
|
44
|
+
ok {pr}.NOT.raise?(Exception)
|
45
|
+
ok {x}.is_a?(Benry::CmdApp::AppOptionSchema)
|
46
|
+
end
|
47
|
+
|
48
|
+
spec "[!tq2ol] adds '-h, --help' option if 'config.option_help' is set." do
|
49
|
+
x = new_gschema(option_help: true)
|
50
|
+
ok {x.find_long_option("help")} != nil
|
51
|
+
ok {x.find_short_option("h")} != nil
|
52
|
+
x = new_gschema(option_help: false)
|
53
|
+
ok {x.find_long_option("help")} == nil
|
54
|
+
ok {x.find_short_option("h")} == nil
|
55
|
+
end
|
56
|
+
|
57
|
+
spec "[!mbtw0] adds '-V, --version' option if 'config.app_version' is set." do
|
58
|
+
x = new_gschema("", "0.0.0")
|
59
|
+
ok {x.find_long_option("version")} != nil
|
60
|
+
ok {x.find_short_option("V")} != nil
|
61
|
+
x = new_gschema("", nil)
|
62
|
+
ok {x.find_long_option("version")} == nil
|
63
|
+
ok {x.find_short_option("V")} == nil
|
64
|
+
end
|
65
|
+
|
66
|
+
spec "[!f5do6] adds '-a, --all' option if 'config.option_all' is set." do
|
67
|
+
x = new_gschema(option_all: true)
|
68
|
+
ok {x.find_long_option("all")} != nil
|
69
|
+
ok {x.find_short_option("a")} != nil
|
70
|
+
x = new_gschema(option_all: false)
|
71
|
+
ok {x.find_long_option("all")} == nil
|
72
|
+
ok {x.find_short_option("a")} == nil
|
73
|
+
end
|
74
|
+
|
75
|
+
spec "[!cracf] adds '-v, --verbose' option if 'config.option_verbose' is set." do
|
76
|
+
x = new_gschema(option_verbose: true)
|
77
|
+
ok {x.find_long_option("verbose")} != nil
|
78
|
+
ok {x.find_short_option("v")} != nil
|
79
|
+
x = new_gschema(option_verbose: false)
|
80
|
+
ok {x.find_long_option("verbose")} == nil
|
81
|
+
ok {x.find_short_option("v")} == nil
|
82
|
+
end
|
83
|
+
|
84
|
+
spec "[!2vil6] adds '-q, --quiet' option if 'config.option_quiet' is set." do
|
85
|
+
x = new_gschema(option_quiet: true)
|
86
|
+
ok {x.find_long_option("quiet")} != nil
|
87
|
+
ok {x.find_short_option("q")} != nil
|
88
|
+
x = new_gschema(option_quiet: false)
|
89
|
+
ok {x.find_long_option("quiet")} == nil
|
90
|
+
ok {x.find_short_option("q")} == nil
|
91
|
+
end
|
92
|
+
|
93
|
+
spec "[!6zw3j] adds '--color=<on|off>' option if 'config.option_color' is set." do
|
94
|
+
x = new_gschema(option_color: true)
|
95
|
+
ok {x.find_long_option("color")} != nil
|
96
|
+
x = new_gschema(option_quiet: false)
|
97
|
+
ok {x.find_long_option("color")} == nil
|
98
|
+
end
|
99
|
+
|
100
|
+
spec "[!29wfy] adds '-D, --debug' option if 'config.option_debug' is set." do
|
101
|
+
x = new_gschema(option_debug: true)
|
102
|
+
ok {x.find_long_option("debug")} != nil
|
103
|
+
ok {x.find_short_option("D")} != nil
|
104
|
+
x = new_gschema(option_debug: false)
|
105
|
+
ok {x.find_long_option("debug")} == nil
|
106
|
+
ok {x.find_short_option("D")} == nil
|
107
|
+
end
|
108
|
+
|
109
|
+
spec "[!s97go] adds '-T, --trace' option if 'config.option_trace' is set." do
|
110
|
+
x = new_gschema(option_trace: true)
|
111
|
+
ok {x.find_long_option("trace")} != nil
|
112
|
+
ok {x.find_short_option("T")} != nil
|
113
|
+
x = new_gschema(option_debug: false)
|
114
|
+
ok {x.find_long_option("trace")} == nil
|
115
|
+
ok {x.find_short_option("T")} == nil
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
topic '#sort_options_in_this_order()' do
|
122
|
+
|
123
|
+
def new_gschema(desc="app test", version="1.0.0")
|
124
|
+
config = Benry::CmdApp::Config.new(desc, version)
|
125
|
+
config.option_all = true
|
126
|
+
config.option_verbose = true
|
127
|
+
config.option_quiet = true
|
128
|
+
config.option_debug = true
|
129
|
+
return Benry::CmdApp::AppOptionSchema.new(config)
|
130
|
+
end
|
131
|
+
|
132
|
+
spec "[!6udxr] sorts options in order of keys specified." do
|
133
|
+
x = new_gschema()
|
134
|
+
keys1 = x.each.collect(&:key)
|
135
|
+
ok {keys1} == [:help, :version, :all, :verbose, :quiet, :debug]
|
136
|
+
x.sort_options_in_this_order(:help, :quiet, :verbose, :all, :trace, :debug, :version)
|
137
|
+
keys2 = x.each.collect(&:key)
|
138
|
+
ok {keys2} == [:help, :quiet, :verbose, :all, :debug, :version]
|
139
|
+
end
|
140
|
+
|
141
|
+
spec "[!8hhuf] options which key doesn't appear in keys are moved at end of options." do
|
142
|
+
x = new_gschema()
|
143
|
+
x.sort_options_in_this_order(:quiet, :verbose, :all, :debug) # missing :help and :version
|
144
|
+
keys = x.each.collect(&:key)
|
145
|
+
ok {keys[-2]} == :help
|
146
|
+
ok {keys[-1]} == :version
|
147
|
+
ok {keys} == [:quiet, :verbose, :all, :debug, :help, :version]
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
topic Benry::CmdApp::Application do
|
157
|
+
include CommonTestingHelper
|
158
|
+
|
159
|
+
class AppTest < Benry::CmdApp::ActionScope
|
160
|
+
@action.("print greeting message")
|
161
|
+
@option.(:lang, "-l, --lang=<en|fr|it>", "language")
|
162
|
+
def sayhello(user="world", lang: "en")
|
163
|
+
case lang
|
164
|
+
when "en" ; puts "Hello, #{user}!"
|
165
|
+
when "fr" ; puts "Bonjour, #{user}!"
|
166
|
+
when "it" ; puts "Ciao, #{user}!"
|
167
|
+
else ; raise "#{lang}: unknown language."
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
before do
|
173
|
+
@config = Benry::CmdApp::Config.new("test app", "1.0.0",
|
174
|
+
app_name: "TestApp", app_command: "testapp",
|
175
|
+
default_action: nil,
|
176
|
+
option_all: true, option_debug: true)
|
177
|
+
@app = Benry::CmdApp::Application.new(@config)
|
178
|
+
end
|
179
|
+
|
180
|
+
def _run_app(*args)
|
181
|
+
sout, serr = capture_sio { @app.run(*args) }
|
182
|
+
ok {serr} == ""
|
183
|
+
return sout
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
topic '#initialize()' do
|
188
|
+
|
189
|
+
spec "[!jkprn] creates option schema object according to config." do
|
190
|
+
c = Benry::CmdApp::Config.new("test", "1.0.0", option_debug: true)
|
191
|
+
app = Benry::CmdApp::Application.new(c)
|
192
|
+
schema = app.instance_variable_get('@schema')
|
193
|
+
ok {schema}.is_a?(Benry::CmdOpt::Schema)
|
194
|
+
items = schema.each.to_a()
|
195
|
+
ok {items[0].key} == :help
|
196
|
+
ok {items[1].key} == :version
|
197
|
+
ok {items[2].key} == :debug
|
198
|
+
ok {schema.option_help()} == <<END
|
199
|
+
-h, --help : print help message
|
200
|
+
-V, --version : print version
|
201
|
+
-D, --debug : debug mode (set $DEBUG_MODE to true)
|
202
|
+
END
|
203
|
+
end
|
204
|
+
|
205
|
+
spec "[!h786g] acceps callback block." do
|
206
|
+
config = Benry::CmdApp::Config.new("test app")
|
207
|
+
n = 0
|
208
|
+
app = Benry::CmdApp::Application.new(config) do |args|
|
209
|
+
n += 1
|
210
|
+
end
|
211
|
+
ok {app.callback}.is_a?(Proc)
|
212
|
+
ok {n} == 0
|
213
|
+
app.callback.call([])
|
214
|
+
ok {n} == 1
|
215
|
+
app.callback.call([])
|
216
|
+
ok {n} == 2
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
topic '#main()' do
|
223
|
+
|
224
|
+
after do
|
225
|
+
$cmdapp_config = nil
|
226
|
+
end
|
227
|
+
|
228
|
+
spec "[!y6q9z] runs action with options." do
|
229
|
+
sout, serr = capture_sio { @app.main(["sayhello", "-l", "it", "Alice"]) }
|
230
|
+
ok {serr} == ""
|
231
|
+
ok {sout} == "Ciao, Alice!\n"
|
232
|
+
end
|
233
|
+
|
234
|
+
spec "[!a7d4w] prints error message with '[ERROR]' prompt." do
|
235
|
+
sout, serr = capture_sio { @app.main(["sayhello", "Alice", "Bob"]) }
|
236
|
+
ok {serr} == "\e[0;31m[ERROR]\e[0m sayhello: Too much arguments (at most 1).\n"
|
237
|
+
ok {sout} == ""
|
238
|
+
end
|
239
|
+
|
240
|
+
spec "[!r7opi] prints filename and line number on where error raised if DefinitionError." do
|
241
|
+
class MainTest1 < Benry::CmdApp::ActionScope
|
242
|
+
prefix "main1"
|
243
|
+
@action.("test")
|
244
|
+
def err1
|
245
|
+
MainTest1.class_eval do
|
246
|
+
@action.("test")
|
247
|
+
@option.(:foo, "--foo", "foo")
|
248
|
+
def err2(bar: nil) # should have keyword parameter 'foo'
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
lineno = __LINE__ - 5
|
254
|
+
sout, serr = capture_sio { @app.main(["main1:err1"]) }
|
255
|
+
ok {sout} == ""
|
256
|
+
serr = serr.sub(/file: \/.*?test\//, 'file: test/')
|
257
|
+
ok {serr} == <<"END"
|
258
|
+
\e[0;31m[ERROR]\e[0m def err2(): Should have keyword parameter 'foo' for '@option.(:foo)', but not.
|
259
|
+
\t\(file: test\/app_test\.rb, line: #{lineno})
|
260
|
+
END
|
261
|
+
end
|
262
|
+
|
263
|
+
spec "[!v0zrf] error location can be filtered by block." do
|
264
|
+
class MainTest2 < Benry::CmdApp::ActionScope
|
265
|
+
prefix "main2"
|
266
|
+
@action.("test")
|
267
|
+
def err2
|
268
|
+
_err2()
|
269
|
+
end
|
270
|
+
def _err2()
|
271
|
+
MainTest2.class_eval do # == lineno2
|
272
|
+
@action.("test")
|
273
|
+
@option.(:foo, "--foo", "foo")
|
274
|
+
def err2x(bar: nil) # == lineno1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
lineno1 = __LINE__ - 5
|
280
|
+
lineno2 = lineno1 - 3
|
281
|
+
## no filter
|
282
|
+
sout, serr = capture_sio { @app.main(["main2:err2"]) }
|
283
|
+
ok {sout} == ""
|
284
|
+
ok {serr} =~ /\t\(file: .*\/app_test\.rb, line: #{lineno1}\)\n/
|
285
|
+
## filter by block
|
286
|
+
sout, serr = capture_sio {
|
287
|
+
@app.main(["main2:err2"]) {|exc| exc.lineno == lineno2 }
|
288
|
+
}
|
289
|
+
ok {sout} == ""
|
290
|
+
ok {serr} =~ /\t\(file: .*\/app_test\.rb, line: #{lineno2}\)\n/
|
291
|
+
end
|
292
|
+
|
293
|
+
spec "[!6ro6n] not catch error when $DEBUG_MODE is on." do
|
294
|
+
bkup = $DEBUG_MODE
|
295
|
+
begin
|
296
|
+
pr = proc { @app.main(["-D", "sayhello", "Alice", "Bob"]) }
|
297
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
298
|
+
"sayhello: Too much arguments (at most 1).")
|
299
|
+
ensure
|
300
|
+
$DEBUG_MODE = bkup
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
spec "[!5oypr] returns 0 as exit code when no errors occurred." do
|
305
|
+
ret = nil
|
306
|
+
sout, serr = capture_sio do
|
307
|
+
ret = @app.main(["sayhello", "Alice", "-l", "it"])
|
308
|
+
end
|
309
|
+
ok {ret} == 0
|
310
|
+
ok {serr} == ""
|
311
|
+
ok {sout} == "Ciao, Alice!\n"
|
312
|
+
end
|
313
|
+
|
314
|
+
spec "[!qk5q5] returns 1 as exit code when error occurred." do
|
315
|
+
ret = nil
|
316
|
+
sout, serr = capture_sio do
|
317
|
+
ret = @app.main(["sayhello", "Alice", "Bob"])
|
318
|
+
end
|
319
|
+
ok {ret} == 1
|
320
|
+
ok {serr} == "\e[0;31m[ERROR]\e[0m sayhello: Too much arguments (at most 1).\n"
|
321
|
+
ok {sout} == ""
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
topic '#run()' do
|
328
|
+
|
329
|
+
class AppRunTest < Benry::CmdApp::ActionScope
|
330
|
+
#
|
331
|
+
@action.("test config")
|
332
|
+
def check_config()
|
333
|
+
puts "$cmdapp_config.class=#{$cmdapp_config.class.name}"
|
334
|
+
end
|
335
|
+
#
|
336
|
+
@action.("test global option parseing")
|
337
|
+
@option.(:help, "-h, --help", "print help")
|
338
|
+
def test_globalopt(help: false)
|
339
|
+
puts "help=#{help}"
|
340
|
+
end
|
341
|
+
#
|
342
|
+
@action.("test debug option")
|
343
|
+
def test_debugopt(help: false)
|
344
|
+
puts "$DEBUG_MODE=#{$DEBUG_MODE}"
|
345
|
+
end
|
346
|
+
#
|
347
|
+
@action.("arity test")
|
348
|
+
def test_arity1(xx, yy, zz=nil)
|
349
|
+
end
|
350
|
+
#
|
351
|
+
@action.("arity test with variable args")
|
352
|
+
def test_arity2(xx, yy, zz=nil, *rest)
|
353
|
+
end
|
354
|
+
#
|
355
|
+
@action.("raises exception")
|
356
|
+
def test_exception1()
|
357
|
+
1/0
|
358
|
+
end
|
359
|
+
#
|
360
|
+
@action.("loop test")
|
361
|
+
def test_loop1()
|
362
|
+
run_action_once("test-loop2")
|
363
|
+
end
|
364
|
+
@action.("loop test")
|
365
|
+
def test_loop2()
|
366
|
+
run_action_once("test-loop1")
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
spec "[!t4ypg] sets $cmdapp_config at beginning." do
|
371
|
+
sout, serr = capture_sio { @app.run("check-config") }
|
372
|
+
ok {serr} == ""
|
373
|
+
ok {sout} == "$cmdapp_config.class=Benry::CmdApp::Config\n"
|
374
|
+
end
|
375
|
+
|
376
|
+
spec "[!pyotc] sets global options to '@global_options'." do
|
377
|
+
ok {@app.instance_variable_get('@global_options')} == nil
|
378
|
+
capture_sio { @app.run("--help") }
|
379
|
+
ok {@app.instance_variable_get('@global_options')} == {:help=>true}
|
380
|
+
end
|
381
|
+
|
382
|
+
spec "[!go9kk] sets global variables according to global options." do
|
383
|
+
config = Benry::CmdApp::Config.new("test app", "1.0.0",
|
384
|
+
option_verbose: true,
|
385
|
+
option_quiet: true,
|
386
|
+
option_debug: true,
|
387
|
+
option_color: true)
|
388
|
+
app = Benry::CmdApp::Application.new(config)
|
389
|
+
bkup = [$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]
|
390
|
+
begin
|
391
|
+
['-v', '--verbose'].each do |x|
|
392
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = nil, nil, nil
|
393
|
+
capture_sio { app.run(x, '-h') }
|
394
|
+
ok {[$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]} == [false, nil, nil]
|
395
|
+
end
|
396
|
+
#
|
397
|
+
['-q', '--quiet'].each do |x|
|
398
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = nil, nil, nil
|
399
|
+
capture_sio { app.run(x, '-h') }
|
400
|
+
ok {[$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]} == [true, nil, nil]
|
401
|
+
end
|
402
|
+
#
|
403
|
+
['-D', '--debug'].each do |x|
|
404
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = nil, nil, nil
|
405
|
+
capture_sio { app.run(x, '-h') }
|
406
|
+
ok {[$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]} == [nil, true, nil]
|
407
|
+
end
|
408
|
+
#
|
409
|
+
['--color', '--color=on'].each do |x|
|
410
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = nil, nil, nil
|
411
|
+
capture_sio { app.run(x, '-h') }
|
412
|
+
ok {[$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]} == [nil, nil, true]
|
413
|
+
end
|
414
|
+
['--color=off'].each do |x|
|
415
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = nil, nil, nil
|
416
|
+
capture_sio { app.run(x, '-h') }
|
417
|
+
ok {[$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE]} == [nil, nil, false]
|
418
|
+
end
|
419
|
+
ensure
|
420
|
+
$QUIET_MODE, $DEBUG_MODE, $COLOR_MODE = bkup
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
spec "[!5iczl] skip actions if help option or version option specified." do
|
425
|
+
def @app.do_callback(args, global_opts)
|
426
|
+
@_called_ = args.dup
|
427
|
+
end
|
428
|
+
capture_sio { @app.run("--help") }
|
429
|
+
ok {@app.instance_variable_get('@_called_')} == nil
|
430
|
+
capture_sio { @app.run("--version") }
|
431
|
+
ok {@app.instance_variable_get('@_called_')} == nil
|
432
|
+
capture_sio { @app.run("sayhello") }
|
433
|
+
ok {@app.instance_variable_get('@_called_')} == ["sayhello"]
|
434
|
+
end
|
435
|
+
|
436
|
+
spec "[!w584g] calls callback method." do
|
437
|
+
def @app.do_callback(args, global_opts)
|
438
|
+
@_called_ = args.dup
|
439
|
+
end
|
440
|
+
ok {@app.instance_variable_get('@_called_')} == nil
|
441
|
+
capture_sio { @app.run("sayhello") }
|
442
|
+
ok {@app.instance_variable_get('@_called_')} == ["sayhello"]
|
443
|
+
end
|
444
|
+
|
445
|
+
spec "[!pbug7] skip actions if callback method throws `:SKIP`." do
|
446
|
+
def @app.do_callback(args, global_opts)
|
447
|
+
@_called1 = args.dup
|
448
|
+
throw :SKIP
|
449
|
+
end
|
450
|
+
def @app.do_find_action(args, global_opts)
|
451
|
+
super
|
452
|
+
@_called2 = args.dup
|
453
|
+
end
|
454
|
+
ok {@app.instance_variable_get('@_called1')} == nil
|
455
|
+
ok {@app.instance_variable_get('@_called2')} == nil
|
456
|
+
capture_sio { @app.run("sayhello") }
|
457
|
+
ok {@app.instance_variable_get('@_called1')} == ["sayhello"]
|
458
|
+
ok {@app.instance_variable_get('@_called2')} == nil
|
459
|
+
end
|
460
|
+
|
461
|
+
spec "[!avxos] prints candidate actions if action name ends with ':'." do
|
462
|
+
class CandidateTest1 < Benry::CmdApp::ActionScope
|
463
|
+
prefix "candi:date1"
|
464
|
+
@action.("test")
|
465
|
+
def bbb(); end
|
466
|
+
@action.("test")
|
467
|
+
def aaa(); end
|
468
|
+
end
|
469
|
+
## without tty
|
470
|
+
sout, serr = capture_sio(tty: false) { @app.run("candi:date1:") }
|
471
|
+
ok {serr} == ""
|
472
|
+
ok {sout} == <<"END"
|
473
|
+
Actions:
|
474
|
+
candi:date1:aaa : test
|
475
|
+
candi:date1:bbb : test
|
476
|
+
END
|
477
|
+
## with tty
|
478
|
+
sout, serr = capture_sio(tty: true) { @app.run("candi:date1:") }
|
479
|
+
ok {serr} == ""
|
480
|
+
ok {sout} == <<"END"
|
481
|
+
\e[34mActions:\e[0m
|
482
|
+
\e[1mcandi:date1:aaa \e[0m : test
|
483
|
+
\e[1mcandi:date1:bbb \e[0m : test
|
484
|
+
END
|
485
|
+
end
|
486
|
+
|
487
|
+
spec "[!eeh0y] candidates are not printed if 'config.feat_candidate' is false." do
|
488
|
+
class CandidateTest5 < Benry::CmdApp::ActionScope
|
489
|
+
prefix "candi:date5"
|
490
|
+
@action.("test b")
|
491
|
+
def bbb(); end
|
492
|
+
@action.("test a")
|
493
|
+
def aaa(); end
|
494
|
+
end
|
495
|
+
## flag is on
|
496
|
+
@app.config.feat_candidate = false
|
497
|
+
pr = proc { @app.run("candi:date5:") }
|
498
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
499
|
+
"candi:date5:: Unknown action.")
|
500
|
+
## flag is off
|
501
|
+
@app.config.feat_candidate = true
|
502
|
+
sout, serr = capture_sio(tty: false) { @app.run("candi:date5:") }
|
503
|
+
ok {serr} == ""
|
504
|
+
ok {sout} == <<"END"
|
505
|
+
Actions:
|
506
|
+
candi:date5:aaa : test a
|
507
|
+
candi:date5:bbb : test b
|
508
|
+
END
|
509
|
+
end
|
510
|
+
|
511
|
+
spec "[!l0g1l] skip actions if no action specified and 'config.default_help' is set." do
|
512
|
+
def @app.do_find_action(args, global_opts)
|
513
|
+
ret = super
|
514
|
+
@_args1 = args.dup
|
515
|
+
@_result = ret
|
516
|
+
ret
|
517
|
+
end
|
518
|
+
def @app.do_run_action(metadata, args, global_opts)
|
519
|
+
ret = super
|
520
|
+
@_args2 = args.dup
|
521
|
+
ret
|
522
|
+
end
|
523
|
+
@app.config.default_help = true
|
524
|
+
capture_sio { @app.run() }
|
525
|
+
ok {@app.instance_variable_get('@_args1')} == []
|
526
|
+
ok {@app.instance_variable_get('@_result')} == nil
|
527
|
+
ok {@app.instance_variable_get('@_args2')} == nil
|
528
|
+
end
|
529
|
+
|
530
|
+
spec "[!x1xgc] run action with options and arguments." do
|
531
|
+
sout, serr = capture_sio { @app.run("sayhello", "Alice", "-l", "it") }
|
532
|
+
ok {serr} == ""
|
533
|
+
ok {sout} == "Ciao, Alice!\n"
|
534
|
+
end
|
535
|
+
|
536
|
+
spec "[!agfdi] reports error when action not found." do
|
537
|
+
pr = proc { @app.run("xxx-yyy") }
|
538
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
539
|
+
"xxx-yyy: Unknown action.")
|
540
|
+
end
|
541
|
+
|
542
|
+
spec "[!v5k56] runs default action if action not specified." do
|
543
|
+
@config.default_action = "sayhello"
|
544
|
+
sout, serr = capture_sio { @app.run() }
|
545
|
+
ok {serr} == ""
|
546
|
+
ok {sout} == "Hello, world!\n"
|
547
|
+
end
|
548
|
+
|
549
|
+
spec "[!o5i3w] reports error when default action not found." do
|
550
|
+
@config.default_action = "xxx-zzz"
|
551
|
+
pr = proc { @app.run() }
|
552
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
553
|
+
"xxx-zzz: Unknown default action.")
|
554
|
+
end
|
555
|
+
|
556
|
+
spec "[!7h0ku] prints help if no action but 'config.default_help' is true." do
|
557
|
+
expected, serr = capture_sio { @app.run("-h") }
|
558
|
+
ok {serr} == ""
|
559
|
+
ok {expected} =~ /^Usage:/
|
560
|
+
#
|
561
|
+
@config.default_help = true
|
562
|
+
sout, serr = capture_sio { @app.run() }
|
563
|
+
ok {serr} == ""
|
564
|
+
ok {sout} == expected
|
565
|
+
end
|
566
|
+
|
567
|
+
spec "[!n60o0] reports error when action nor default action not specified." do
|
568
|
+
@config.default_action = nil
|
569
|
+
pr = proc { @app.run() }
|
570
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
571
|
+
"testapp: Action name required (run `testapp -h` for details).")
|
572
|
+
end
|
573
|
+
|
574
|
+
spec "[!hk6iu] unsets $cmdapp_config at end." do
|
575
|
+
bkup = $cmdapp_config
|
576
|
+
$cmdapp_config = nil
|
577
|
+
begin
|
578
|
+
sout, serr = capture_sio { @app.run("check-config") }
|
579
|
+
ok {sout} == "$cmdapp_config.class=Benry::CmdApp::Config\n"
|
580
|
+
ok {$cmdapp_config} == nil
|
581
|
+
ensure
|
582
|
+
$cmdapp_config = bkup
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
spec "[!wv22u] calls teardown method at end of running action." do
|
587
|
+
def @app.do_teardown(*args)
|
588
|
+
@_args = args
|
589
|
+
end
|
590
|
+
ok {@app.instance_variable_get('@_args')} == nil
|
591
|
+
sout, serr = capture_sio { @app.run("check-config") }
|
592
|
+
ok {@app.instance_variable_get('@_args')} == [nil]
|
593
|
+
end
|
594
|
+
|
595
|
+
spec "[!dhba4] calls teardown method even if exception raised." do
|
596
|
+
def @app.do_teardown(*args)
|
597
|
+
@_args = args
|
598
|
+
end
|
599
|
+
ok {@app.instance_variable_get('@_args')} == nil
|
600
|
+
pr = proc { @app.run("test-exception1") }
|
601
|
+
ok {pr}.raise?(ZeroDivisionError) do |exc|
|
602
|
+
ok {@app.instance_variable_get('@_args')} == [exc]
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
end
|
607
|
+
|
608
|
+
|
609
|
+
topic '#help_message()' do
|
610
|
+
|
611
|
+
spec "[!owg9y] returns help message." do
|
612
|
+
msg = @app.help_message()
|
613
|
+
msg = uncolorize(msg)
|
614
|
+
ok {msg}.start_with?(<<END)
|
615
|
+
TestApp (1.0.0) -- test app
|
616
|
+
|
617
|
+
Usage:
|
618
|
+
$ testapp [<options>] [<action> [<arguments>...]]
|
619
|
+
|
620
|
+
Options:
|
621
|
+
-h, --help : print help message
|
622
|
+
-V, --version : print version
|
623
|
+
-a, --all : list all actions including private (hidden) ones
|
624
|
+
-D, --debug : debug mode (set $DEBUG_MODE to true)
|
625
|
+
|
626
|
+
Actions:
|
627
|
+
END
|
628
|
+
end
|
629
|
+
|
630
|
+
end
|
631
|
+
|
632
|
+
|
633
|
+
topic '#do_create_global_option_schema()' do
|
634
|
+
|
635
|
+
spec "[!u3zdg] creates global option schema object according to config." do
|
636
|
+
config = Benry::CmdApp::Config.new("test app", "1.0.0",
|
637
|
+
option_all: true, option_quiet: true)
|
638
|
+
app = Benry::CmdApp::Application.new(config)
|
639
|
+
x = app.__send__(:do_create_global_option_schema, config)
|
640
|
+
ok {x}.is_a?(Benry::CmdApp::AppOptionSchema)
|
641
|
+
ok {x.find_long_option("all")} != nil
|
642
|
+
ok {x.find_long_option("quiet")} != nil
|
643
|
+
ok {x.find_long_option("verbose")} == nil
|
644
|
+
ok {x.find_long_option("debug")} == nil
|
645
|
+
end
|
646
|
+
|
647
|
+
end
|
648
|
+
|
649
|
+
|
650
|
+
topic '#do_create_help_message_builder()' do
|
651
|
+
|
652
|
+
spec "[!pk5da] creates help message builder object." do
|
653
|
+
config = Benry::CmdApp::Config.new("test app", "1.0.0",
|
654
|
+
option_all: true, option_quiet: true)
|
655
|
+
app = Benry::CmdApp::Application.new(config)
|
656
|
+
x = app.__send__(:do_create_help_message_builder, config, app.schema)
|
657
|
+
ok {x}.is_a?(Benry::CmdApp::AppHelpBuilder)
|
658
|
+
end
|
659
|
+
|
660
|
+
end
|
661
|
+
|
662
|
+
|
663
|
+
topic '#do_parse_global_options()' do
|
664
|
+
|
665
|
+
spec "[!5br6t] parses only global options and not parse action options." do
|
666
|
+
sout, serr = capture_sio { @app.run("test-globalopt", "--help") }
|
667
|
+
ok {serr} == ""
|
668
|
+
ok {sout} == "help=true\n"
|
669
|
+
end
|
670
|
+
|
671
|
+
spec "[!kklah] raises InvalidOptionError if global option value is invalid." do
|
672
|
+
pr = proc { @app.run("-hoge", "test-globalopt") }
|
673
|
+
ok {pr}.raise?(Benry::CmdApp::InvalidOptionError, "-o: Unknown option.")
|
674
|
+
end
|
675
|
+
|
676
|
+
end
|
677
|
+
|
678
|
+
|
679
|
+
topic '#do_toggle_global_switches()' do
|
680
|
+
|
681
|
+
before do
|
682
|
+
@config = Benry::CmdApp::Config.new("test app", "1.0.0",
|
683
|
+
option_verbose: true,
|
684
|
+
option_quiet: true,
|
685
|
+
option_debug: true,
|
686
|
+
option_color: true,
|
687
|
+
option_trace: true)
|
688
|
+
@app = Benry::CmdApp::Application.new(@config)
|
689
|
+
end
|
690
|
+
|
691
|
+
spec "[!j6u5x] sets $QUIET_MODE to false if '-v' or '--verbose' specified." do
|
692
|
+
bkup = $QUIET_MODE
|
693
|
+
begin
|
694
|
+
["-v", "--verbose"].each do |opt|
|
695
|
+
$QUIET_MODE = true
|
696
|
+
sout, serr = capture_sio { @app.run(opt, "test-debugopt") }
|
697
|
+
ok {serr} == ""
|
698
|
+
ok {$QUIET_MODE} == false
|
699
|
+
end
|
700
|
+
ensure
|
701
|
+
$QUIET_MODE = bkup
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
spec "[!p1l1i] sets $QUIET_MODE to true if '-q' or '--quiet' specified." do
|
706
|
+
bkup = $QUIET_MODE
|
707
|
+
begin
|
708
|
+
["-q", "--quiet"].each do |opt|
|
709
|
+
$QUIET_MODE = nil
|
710
|
+
sout, serr = capture_sio { @app.run(opt, "test-debugopt") }
|
711
|
+
ok {serr} == ""
|
712
|
+
ok {$QUIET_MODE} == true
|
713
|
+
end
|
714
|
+
ensure
|
715
|
+
$QUIET_MODE = bkup
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
spec "[!2zvf9] sets $COLOR_MODE to true/false according to '--color' option." do
|
720
|
+
bkup = $COLOR_MODE
|
721
|
+
begin
|
722
|
+
[["--color", true], ["--color=on", true], ["--color=off", false]].each do |opt, val|
|
723
|
+
$COLOR_MODE = !val
|
724
|
+
sout, serr = capture_sio { @app.run(opt, "test-debugopt") }
|
725
|
+
ok {serr} == ""
|
726
|
+
ok {$COLOR_MODE} == val
|
727
|
+
end
|
728
|
+
ensure
|
729
|
+
$COLOR_MODE = bkup
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
spec "[!ywl1a] sets $DEBUG_MODE to true if '-D' or '--debug' specified." do
|
734
|
+
bkup = $DEBUG_MODE
|
735
|
+
begin
|
736
|
+
["-D", "--debug"].each do |opt|
|
737
|
+
$DEBUG_MODE = false
|
738
|
+
sout, serr = capture_sio { @app.run(opt, "test-debugopt") }
|
739
|
+
ok {serr} == ""
|
740
|
+
ok {sout} == "$DEBUG_MODE=true\n"
|
741
|
+
ok {$DEBUG_MODE} == true
|
742
|
+
end
|
743
|
+
ensure
|
744
|
+
$DEBUG_MODE = bkup
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
spec "[!8trmz] sets $TRACE_MODE to true if '-T' or '--trace' specified." do
|
749
|
+
bkup = $TRACE_MODE
|
750
|
+
begin
|
751
|
+
["-T", "--trace"].each do |opt|
|
752
|
+
$TRACE_MODE = false
|
753
|
+
sout, serr = capture_sio { @app.run(opt, "test-debugopt") }
|
754
|
+
ok {serr} == ""
|
755
|
+
ok {$TRACE_MODE} == true
|
756
|
+
end
|
757
|
+
ensure
|
758
|
+
$TRACE_MODE = bkup
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
end
|
763
|
+
|
764
|
+
|
765
|
+
topic '#do_handle_global_options()' do
|
766
|
+
|
767
|
+
def new_app()
|
768
|
+
kws = {
|
769
|
+
app_name: "TestApp",
|
770
|
+
app_command: "testapp",
|
771
|
+
option_all: true,
|
772
|
+
option_verbose: true,
|
773
|
+
option_quiet: true,
|
774
|
+
option_color: true,
|
775
|
+
option_debug: true,
|
776
|
+
default_action: nil,
|
777
|
+
}
|
778
|
+
config = Benry::CmdApp::Config.new("test app", "1.0.0", **kws)
|
779
|
+
return Benry::CmdApp::Application.new(config)
|
780
|
+
end
|
781
|
+
|
782
|
+
spec "[!xvj6s] prints help message if '-h' or '--help' specified." do
|
783
|
+
expected = <<"END"
|
784
|
+
TestApp (1.0.0) -- test app
|
785
|
+
|
786
|
+
Usage:
|
787
|
+
$ testapp [<options>] [<action> [<arguments>...]]
|
788
|
+
|
789
|
+
Options:
|
790
|
+
-h, --help : print help message
|
791
|
+
-V, --version : print version
|
792
|
+
-a, --all : list all actions including private (hidden) ones
|
793
|
+
-v, --verbose : verbose mode
|
794
|
+
-q, --quiet : quiet mode
|
795
|
+
--color[=<on|off>] : enable/disable color
|
796
|
+
-D, --debug : debug mode (set $DEBUG_MODE to true)
|
797
|
+
|
798
|
+
Actions:
|
799
|
+
END
|
800
|
+
app = new_app()
|
801
|
+
["-h", "--help"].each do |opt|
|
802
|
+
sout, serr = capture_sio { app.run(opt) }
|
803
|
+
ok {serr} == ""
|
804
|
+
ok {sout}.start_with?(expected)
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
spec "[!lpoz7] prints help message of action if action name specified with help option." do
|
809
|
+
expected = <<"END"
|
810
|
+
testapp sayhello -- print greeting message
|
811
|
+
|
812
|
+
Usage:
|
813
|
+
$ testapp sayhello [<options>] [<user>]
|
814
|
+
|
815
|
+
Options:
|
816
|
+
-l, --lang=<en|fr|it> : language
|
817
|
+
END
|
818
|
+
app = new_app()
|
819
|
+
["-h", "--help"].each do |opt|
|
820
|
+
sout, serr = capture_sio { app.run(opt, "sayhello") }
|
821
|
+
ok {serr} == ""
|
822
|
+
ok {sout} == expected
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
spec "[!fslsy] prints version if '-V' or '--version' specified." do
|
827
|
+
app = new_app()
|
828
|
+
["-V", "--version"].each do |opt|
|
829
|
+
sout, serr = capture_sio { app.run(opt, "xxx") }
|
830
|
+
ok {serr} == ""
|
831
|
+
ok {sout} == "1.0.0\n"
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
end
|
836
|
+
|
837
|
+
|
838
|
+
topic '#do_callback()' do
|
839
|
+
|
840
|
+
def new_app(&block)
|
841
|
+
@config = Benry::CmdApp::Config.new("test app", "1.0.0")
|
842
|
+
return Benry::CmdApp::Application.new(@config, &block)
|
843
|
+
end
|
844
|
+
|
845
|
+
spec "[!xwo0v] calls callback if provided." do
|
846
|
+
called = nil
|
847
|
+
app = new_app do |args, global_opts, config|
|
848
|
+
called = [args.dup, global_opts, config]
|
849
|
+
end
|
850
|
+
ok {called} == nil
|
851
|
+
without_tty { app.run("sayhello") }
|
852
|
+
ok {called} != nil
|
853
|
+
ok {called[0]} == ["sayhello"]
|
854
|
+
ok {called[1]} == {}
|
855
|
+
ok {called[2]} == @config
|
856
|
+
end
|
857
|
+
|
858
|
+
spec "[!lljs1] calls callback only once." do
|
859
|
+
n = 0
|
860
|
+
app = new_app do |args, global_opts, config|
|
861
|
+
n += 1
|
862
|
+
end
|
863
|
+
ok {n} == 0
|
864
|
+
without_tty { app.run("sayhello") }
|
865
|
+
ok {n} == 1
|
866
|
+
without_tty { app.run("sayhello") }
|
867
|
+
ok {n} == 1
|
868
|
+
without_tty { app.run("sayhello") }
|
869
|
+
ok {n} == 1
|
870
|
+
end
|
871
|
+
|
872
|
+
end
|
873
|
+
|
874
|
+
|
875
|
+
topic '#do_find_action()' do
|
876
|
+
|
877
|
+
spec "[!bm8np] returns action metadata." do
|
878
|
+
x = @app.__send__(:do_find_action, ["sayhello"], {})
|
879
|
+
ok {x}.is_a?(Benry::CmdApp::ActionMetadata)
|
880
|
+
ok {x.name} == "sayhello"
|
881
|
+
end
|
882
|
+
|
883
|
+
spec "[!vl0zr] error when action not found." do
|
884
|
+
pr = proc { @app.__send__(:do_find_action, ["hiyo"], {}) }
|
885
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
886
|
+
"hiyo: Unknown action.")
|
887
|
+
end
|
888
|
+
|
889
|
+
spec "[!gucj7] if no action specified, finds default action instead." do
|
890
|
+
@app.config.default_action = "sayhello"
|
891
|
+
x = @app.__send__(:do_find_action, [], {})
|
892
|
+
ok {x}.is_a?(Benry::CmdApp::ActionMetadata)
|
893
|
+
ok {x.name} == "sayhello"
|
894
|
+
end
|
895
|
+
|
896
|
+
spec "[!388rs] error when default action not found." do
|
897
|
+
@app.config.default_action = "hiyo"
|
898
|
+
pr = proc { @app.__send__(:do_find_action, [], {}) }
|
899
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
900
|
+
"hiyo: Unknown default action.")
|
901
|
+
end
|
902
|
+
|
903
|
+
spec "[!drmls] returns nil if no action specified but 'config.default_help' is set." do
|
904
|
+
@app.config.default_action = nil
|
905
|
+
@app.config.default_help = true
|
906
|
+
x = @app.__send__(:do_find_action, [], {})
|
907
|
+
ok {x} == nil
|
908
|
+
end
|
909
|
+
|
910
|
+
spec "[!hs589] error when action nor default action not specified." do
|
911
|
+
@app.config.default_action = nil
|
912
|
+
@app.config.default_help = false
|
913
|
+
pr = proc { @app.__send__(:do_find_action, [], {}) }
|
914
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
915
|
+
"testapp: Action name required (run `testapp -h` for details).")
|
916
|
+
end
|
917
|
+
|
918
|
+
end
|
919
|
+
|
920
|
+
|
921
|
+
topic '#do_run_action()' do
|
922
|
+
|
923
|
+
spec "[!62gv9] parses action options even if specified after args." do
|
924
|
+
sout, serr = capture_sio { @app.run("sayhello", "Alice", "-l", "it") }
|
925
|
+
ok {serr} == ""
|
926
|
+
ok {sout} == "Ciao, Alice!\n"
|
927
|
+
end
|
928
|
+
|
929
|
+
spec "[!6mlol] error if action requries argument but nothing specified." do
|
930
|
+
pr = proc { @app.run("test-arity1") }
|
931
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
932
|
+
"test-arity1: Argument required.")
|
933
|
+
end
|
934
|
+
|
935
|
+
spec "[!72jla] error if action requires N args but specified less than N args." do
|
936
|
+
pr = proc { @app.run("test-arity1", "foo") }
|
937
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
938
|
+
"test-arity1: Too less arguments (at least 2).")
|
939
|
+
end
|
940
|
+
|
941
|
+
spec "[!zawxe] error if action requires N args but specified over than N args." do
|
942
|
+
pr = proc { @app.run("test-arity1", "foo", "bar", "baz", "boo") }
|
943
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
944
|
+
"test-arity1: Too much arguments (at most 3).")
|
945
|
+
end
|
946
|
+
|
947
|
+
spec "[!y97o3] action can take any much args if action has variable arg." do
|
948
|
+
pr = proc {
|
949
|
+
capture_sio { @app.run("test-arity2", "foo", "bar", "baz", "boo") }
|
950
|
+
}
|
951
|
+
ok {pr}.NOT.raise?(Exception)
|
952
|
+
end
|
953
|
+
|
954
|
+
spec "[!cf45e] runs action with arguments and options." do
|
955
|
+
sout, serr = capture_sio { @app.run("sayhello", "-l", "it", "Bob") }
|
956
|
+
ok {serr} == ""
|
957
|
+
ok {sout} == "Ciao, Bob!\n"
|
958
|
+
end
|
959
|
+
|
960
|
+
spec "[!tsal4] detects looped action." do
|
961
|
+
pr = proc { @app.run("test-loop1") }
|
962
|
+
ok {pr}.raise?(Benry::CmdApp::LoopedActionError,
|
963
|
+
"test-loop1: Action loop detected.")
|
964
|
+
end
|
965
|
+
|
966
|
+
end
|
967
|
+
|
968
|
+
|
969
|
+
topic '#do_print_help_message()' do
|
970
|
+
|
971
|
+
spec "[!eabis] prints help message of action if action name provided." do
|
972
|
+
sout, serr = capture_sio { @app.run("-h", "sayhello") }
|
973
|
+
ok {serr} == ""
|
974
|
+
ok {sout} == <<'END'
|
975
|
+
testapp sayhello -- print greeting message
|
976
|
+
|
977
|
+
Usage:
|
978
|
+
$ testapp sayhello [<options>] [<user>]
|
979
|
+
|
980
|
+
Options:
|
981
|
+
-l, --lang=<en|fr|it> : language
|
982
|
+
END
|
983
|
+
end
|
984
|
+
|
985
|
+
spec "[!cgxkb] error if action for help option not found." do
|
986
|
+
["-h", "--help"].each do |opt|
|
987
|
+
pr = proc { @app.run(opt, "xhello") }
|
988
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
989
|
+
"xhello: Action not found.")
|
990
|
+
end
|
991
|
+
end
|
992
|
+
|
993
|
+
spec "[!nv0x3] prints help message of command if action name not provided." do
|
994
|
+
sout, serr = capture_sio { @app.run("-h") }
|
995
|
+
ok {serr} == ""
|
996
|
+
ok {sout}.start_with?(<<'END')
|
997
|
+
TestApp (1.0.0) -- test app
|
998
|
+
|
999
|
+
Usage:
|
1000
|
+
$ testapp [<options>] [<action> [<arguments>...]]
|
1001
|
+
|
1002
|
+
Options:
|
1003
|
+
-h, --help : print help message
|
1004
|
+
-V, --version : print version
|
1005
|
+
-a, --all : list all actions including private (hidden) ones
|
1006
|
+
-D, --debug : debug mode (set $DEBUG_MODE to true)
|
1007
|
+
|
1008
|
+
Actions:
|
1009
|
+
END
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
spec "[!4qs7y] shows private (hidden) actions/options if '--all' option specified." do
|
1013
|
+
class HiddenTest < Benry::CmdApp::ActionScope
|
1014
|
+
private
|
1015
|
+
@action.("hidden test")
|
1016
|
+
@option.(:_trace, "-T", "enable tracing")
|
1017
|
+
def hidden1(_trace: false)
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
#
|
1021
|
+
ok {_run_app("-h", "--all")} =~ /^ hidden1 +: hidden test$/
|
1022
|
+
ok {_run_app("--help", "-a")} =~ /^ hidden1 +: hidden test$/
|
1023
|
+
ok {_run_app("-h")} !~ /^ hidden1 +: hidden test$/
|
1024
|
+
#
|
1025
|
+
ok {_run_app("-ha", "hidden1")} =~ /^ -T +: enable tracing$/
|
1026
|
+
ok {_run_app("-h", "--all", "hidden1")} =~ /^ -T +: enable tracing$/
|
1027
|
+
ok {_run_app("--help", "hidden1")} !~ /^ -T +: enable tracing$/
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
spec "[!l4d6n] `all` flag should be true or false, not nil." do
|
1031
|
+
config = Benry::CmdApp::Config.new("test app", "1.0.0", option_all: true)
|
1032
|
+
app = Benry::CmdApp::Application.new(config)
|
1033
|
+
def app.help_message(all)
|
1034
|
+
@_all_ = all
|
1035
|
+
super
|
1036
|
+
end
|
1037
|
+
msg = without_tty { app.run("-h") }
|
1038
|
+
ok {app.instance_variable_get('@_all_')} != nil
|
1039
|
+
ok {app.instance_variable_get('@_all_')} == false
|
1040
|
+
#
|
1041
|
+
msg = without_tty { app.run("-ha") }
|
1042
|
+
ok {app.instance_variable_get('@_all_')} != nil
|
1043
|
+
ok {app.instance_variable_get('@_all_')} == true
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
spec "[!efaws] prints colorized help message when stdout is a tty." do
|
1047
|
+
sout, serr = capture_sio(tty: true) { @app.run("-h") }
|
1048
|
+
ok {serr} == ""
|
1049
|
+
ok {sout}.include?(<<"END")
|
1050
|
+
\e[34mUsage:\e[0m
|
1051
|
+
$ \e[1mtestapp\e[0m [<options>] [<action> [<arguments>...]]
|
1052
|
+
END
|
1053
|
+
ok {sout}.include?(<<"END")
|
1054
|
+
\e[34mOptions:\e[0m
|
1055
|
+
\e[1m-h, --help \e[0m : print help message
|
1056
|
+
\e[1m-V, --version \e[0m : print version
|
1057
|
+
END
|
1058
|
+
ok {sout}.include?(<<"END")
|
1059
|
+
\e[34mActions:\e[0m
|
1060
|
+
END
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
spec "[!9vdy1] prints non-colorized help message when stdout is not a tty." do
|
1064
|
+
sout, serr = capture_sio(tty: false) { @app.run("-h") }
|
1065
|
+
ok {serr} == ""
|
1066
|
+
ok {sout}.include?(<<"END")
|
1067
|
+
Usage:
|
1068
|
+
$ testapp [<options>] [<action> [<arguments>...]]
|
1069
|
+
END
|
1070
|
+
ok {sout}.include?(<<"END")
|
1071
|
+
Options:
|
1072
|
+
-h, --help : print help message
|
1073
|
+
-V, --version : print version
|
1074
|
+
END
|
1075
|
+
ok {sout}.include?(<<"END")
|
1076
|
+
Actions:
|
1077
|
+
END
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
spec "[!gsdcu] prints colorized help message when '--color[=on]' specified." do
|
1081
|
+
@config.option_color = true
|
1082
|
+
app = Benry::CmdApp::Application.new(@config)
|
1083
|
+
bkup = $COLOR_MODE
|
1084
|
+
begin
|
1085
|
+
sout, serr = capture_sio(tty: false) { app.run("-h", "--color") }
|
1086
|
+
ok {serr} == ""
|
1087
|
+
ok {sout}.include?(<<"END")
|
1088
|
+
\e[34mUsage:\e[0m
|
1089
|
+
$ \e[1mtestapp\e[0m [<options>] [<action> [<arguments>...]]
|
1090
|
+
END
|
1091
|
+
ok {sout}.include?(<<"END")
|
1092
|
+
\e[34mOptions:\e[0m
|
1093
|
+
\e[1m-h, --help \e[0m : print help message
|
1094
|
+
\e[1m-V, --version \e[0m : print version
|
1095
|
+
END
|
1096
|
+
ok {sout}.include?(<<"END")
|
1097
|
+
\e[34mActions:\e[0m
|
1098
|
+
END
|
1099
|
+
ensure
|
1100
|
+
$COLOR_MODE = bkup
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
spec "[!be8y2] prints non-colorized help message when '--color=off' specified." do
|
1105
|
+
@config.option_color = true
|
1106
|
+
app = Benry::CmdApp::Application.new(@config)
|
1107
|
+
bkup = $COLOR_MODE
|
1108
|
+
begin
|
1109
|
+
sout, serr = capture_sio(tty: true) { app.run("-h", "--color=off") }
|
1110
|
+
ok {serr} == ""
|
1111
|
+
ok {sout}.include?(<<"END")
|
1112
|
+
Usage:
|
1113
|
+
$ testapp [<options>] [<action> [<arguments>...]]
|
1114
|
+
END
|
1115
|
+
ok {sout}.include?(<<"END")
|
1116
|
+
Options:
|
1117
|
+
-h, --help : print help message
|
1118
|
+
-V, --version : print version
|
1119
|
+
END
|
1120
|
+
ok {sout}.include?(<<"END")
|
1121
|
+
Actions:
|
1122
|
+
END
|
1123
|
+
ensure
|
1124
|
+
$COLOR_MODE = bkup
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
|
1131
|
+
topic '#do_validate_actions()' do
|
1132
|
+
|
1133
|
+
spec "[!6xhvt] reports warning at end of help message." do
|
1134
|
+
class ValidateActionTest1 < Benry::CmdApp::ActionScope
|
1135
|
+
prefix "validate1", alias_of: :test
|
1136
|
+
@action.("test")
|
1137
|
+
def test1(); end
|
1138
|
+
end
|
1139
|
+
@app.config.default_help = true
|
1140
|
+
begin
|
1141
|
+
[["-h"], []].each do |args|
|
1142
|
+
sout, serr = capture_sio { @app.run(*args) }
|
1143
|
+
ok {serr} == <<'END'
|
1144
|
+
|
1145
|
+
** [warning] in 'ValidateActionTest1' class, `alias_of: :test` specified but corresponding action not exist.
|
1146
|
+
END
|
1147
|
+
end
|
1148
|
+
ensure
|
1149
|
+
ValidateActionTest1.class_eval { @__aliasof__ = nil }
|
1150
|
+
end
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
spec "[!iy241] reports warning if `alias_of:` specified in action class but corresponding action not exist." do
|
1154
|
+
class ValidateActionTest2 < Benry::CmdApp::ActionScope
|
1155
|
+
prefix "validate2", alias_of: :test2
|
1156
|
+
@action.("test")
|
1157
|
+
def test(); end
|
1158
|
+
end
|
1159
|
+
begin
|
1160
|
+
sout, serr = capture_sio { @app.__send__(:do_validate_actions, [], {}) }
|
1161
|
+
ok {serr} == <<'END'
|
1162
|
+
|
1163
|
+
** [warning] in 'ValidateActionTest2' class, `alias_of: :test2` specified but corresponding action not exist.
|
1164
|
+
END
|
1165
|
+
ensure
|
1166
|
+
ValidateActionTest2.class_eval { @__aliasof__ = nil }
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
spec "[!h7lon] reports warning if `action:` specified in action class but corresponding action not exist." do
|
1171
|
+
class ValidateActionTest3 < Benry::CmdApp::ActionScope
|
1172
|
+
prefix "validate3", action: :test3
|
1173
|
+
@action.("test")
|
1174
|
+
def test(); end
|
1175
|
+
end
|
1176
|
+
begin
|
1177
|
+
sout, serr = capture_sio { @app.__send__(:do_validate_actions, [], {}) }
|
1178
|
+
ok {serr} == <<'END'
|
1179
|
+
|
1180
|
+
** [warning] in 'ValidateActionTest3' class, `action: :test3` specified but corresponding action not exist.
|
1181
|
+
END
|
1182
|
+
ensure
|
1183
|
+
ValidateActionTest3.class_eval { @__default__ = nil }
|
1184
|
+
end
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
|
1190
|
+
topic '#do_print_candidates()' do
|
1191
|
+
|
1192
|
+
spec "[!0e8vt] prints candidate action names including prefix name without tailing ':'." do
|
1193
|
+
class CandidateTest2 < Benry::CmdApp::ActionScope
|
1194
|
+
prefix "candi:date2", action: :eee
|
1195
|
+
@action.("test1")
|
1196
|
+
def ddd(); end
|
1197
|
+
@action.("test2")
|
1198
|
+
def ccc(); end
|
1199
|
+
@action.("test3")
|
1200
|
+
def eee(); end
|
1201
|
+
end
|
1202
|
+
sout, serr = capture_sio do
|
1203
|
+
@app.__send__(:do_print_candidates, ["candi:date2:"], {})
|
1204
|
+
end
|
1205
|
+
ok {serr} == ""
|
1206
|
+
ok {sout} == <<"END"
|
1207
|
+
Actions:
|
1208
|
+
candi:date2 : test3
|
1209
|
+
candi:date2:ccc : test2
|
1210
|
+
candi:date2:ddd : test1
|
1211
|
+
END
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
spec "[!85i5m] candidate actions should include alias names." do
|
1215
|
+
class CandidateTest3 < Benry::CmdApp::ActionScope
|
1216
|
+
prefix "candi:date3", action: :ggg
|
1217
|
+
@action.("test1")
|
1218
|
+
def hhh(); end
|
1219
|
+
@action.("test2")
|
1220
|
+
def fff(); end
|
1221
|
+
@action.("test3")
|
1222
|
+
def ggg(); end
|
1223
|
+
end
|
1224
|
+
Benry::CmdApp.action_alias("pupu", "candi:date3:fff")
|
1225
|
+
Benry::CmdApp.action_alias("popo", "candi:date3:fff")
|
1226
|
+
Benry::CmdApp.action_alias("candi:date3:xxx", "candi:date3:hhh")
|
1227
|
+
sout, serr = capture_sio do
|
1228
|
+
@app.__send__(:do_print_candidates, ["candi:date3:"], {})
|
1229
|
+
end
|
1230
|
+
ok {serr} == ""
|
1231
|
+
ok {sout} == <<"END"
|
1232
|
+
Actions:
|
1233
|
+
candi:date3 : test3
|
1234
|
+
candi:date3:fff : test2
|
1235
|
+
(alias: pupu, popo)
|
1236
|
+
candi:date3:hhh : test1
|
1237
|
+
(alias: candi:date3:xxx)
|
1238
|
+
candi:date3:xxx : alias of 'candi:date3:hhh' action
|
1239
|
+
END
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
spec "[!i2azi] raises error when no candidate actions found." do
|
1243
|
+
pr = proc do
|
1244
|
+
@app.__send__(:do_print_candidates, ["candi:date9:"], {})
|
1245
|
+
end
|
1246
|
+
ok {pr}.raise?(Benry::CmdApp::CommandError,
|
1247
|
+
"No actions starting with 'candi:date9:'.")
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
spec "[!k3lw0] private (hidden) action should not be printed as candidates." do
|
1251
|
+
class CandidateTest4 < Benry::CmdApp::ActionScope
|
1252
|
+
prefix "candi:date4"
|
1253
|
+
@action.("test1")
|
1254
|
+
def kkk(); end
|
1255
|
+
private
|
1256
|
+
@action.("test2")
|
1257
|
+
def iii(); end
|
1258
|
+
public
|
1259
|
+
@action.("test3")
|
1260
|
+
def jjj(); end
|
1261
|
+
end
|
1262
|
+
sout, serr = capture_sio do
|
1263
|
+
@app.__send__(:do_print_candidates, ["candi:date4:"], {})
|
1264
|
+
end
|
1265
|
+
ok {serr} == ""
|
1266
|
+
ok {sout} == <<"END"
|
1267
|
+
Actions:
|
1268
|
+
candi:date4:jjj : test3
|
1269
|
+
candi:date4:kkk : test1
|
1270
|
+
END
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
spec "[!j4b54] shows candidates in strong format if important." do
|
1274
|
+
class CandidateTest6 < Benry::CmdApp::ActionScope
|
1275
|
+
prefix "candi:date6"
|
1276
|
+
@action.("test1")
|
1277
|
+
def t1(); end
|
1278
|
+
@action.("test2", important: true)
|
1279
|
+
def t2(); end
|
1280
|
+
end
|
1281
|
+
Benry::CmdApp.action_alias("candi:date6", "candi:date6:t2")
|
1282
|
+
sout, serr = capture_sio(tty: true) do
|
1283
|
+
@app.__send__(:do_print_candidates, ["candi:date6:"], {})
|
1284
|
+
end
|
1285
|
+
ok {serr} == ""
|
1286
|
+
ok {sout} == <<END
|
1287
|
+
\e[34mActions:\e[0m
|
1288
|
+
\e[1m\e[4mcandi:date6\e[0m \e[0m : alias of 'candi:date6:t2' action
|
1289
|
+
\e[1mcandi:date6:t1 \e[0m : test1
|
1290
|
+
\e[1m\e[4mcandi:date6:t2\e[0m \e[0m : test2
|
1291
|
+
(alias: candi:date6)
|
1292
|
+
END
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
spec "[!q3819] shows candidates in weak format if not important." do
|
1296
|
+
class CandidateTest7 < Benry::CmdApp::ActionScope
|
1297
|
+
prefix "candi:date7"
|
1298
|
+
@action.("test1")
|
1299
|
+
def t1(); end
|
1300
|
+
@action.("test2", important: false)
|
1301
|
+
def t2(); end
|
1302
|
+
end
|
1303
|
+
Benry::CmdApp.action_alias("candi:date7", "candi:date7:t2")
|
1304
|
+
sout, serr = capture_sio(tty: true) do
|
1305
|
+
@app.__send__(:do_print_candidates, ["candi:date7:"], {})
|
1306
|
+
end
|
1307
|
+
ok {serr} == ""
|
1308
|
+
ok {sout} == <<END
|
1309
|
+
\e[34mActions:\e[0m
|
1310
|
+
\e[1m\e[2mcandi:date7\e[0m \e[0m : alias of 'candi:date7:t2' action
|
1311
|
+
\e[1mcandi:date7:t1 \e[0m : test1
|
1312
|
+
\e[1m\e[2mcandi:date7:t2\e[0m \e[0m : test2
|
1313
|
+
(alias: candi:date7)
|
1314
|
+
END
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
|
1320
|
+
topic '#do_setup()' do
|
1321
|
+
|
1322
|
+
spec "[!pkio4] sets config object to '$cmdapp_config'." do
|
1323
|
+
$cmdapp_config = nil
|
1324
|
+
@app.__send__(:do_setup,)
|
1325
|
+
ok {$cmdapp_config} != nil
|
1326
|
+
ok {$cmdapp_config} == @app.config
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
spec "[!qwjjv] sets application object to '$cmdapp_application'." do
|
1330
|
+
$cmdapp_application = nil
|
1331
|
+
@app.__send__(:do_setup,)
|
1332
|
+
ok {$cmdapp_application} != nil
|
1333
|
+
ok {$cmdapp_application} == @app
|
1334
|
+
end
|
1335
|
+
|
1336
|
+
spec "[!kqfn1] remove built-in 'help' action if `config.help_action == false`." do
|
1337
|
+
ameta = Benry::CmdApp::INDEX.get_action("help")
|
1338
|
+
ok {Benry::CmdApp::INDEX.action_exist?("help")} == true
|
1339
|
+
begin
|
1340
|
+
@config.help_action = false
|
1341
|
+
@app.__send__(:do_setup,)
|
1342
|
+
ok {Benry::CmdApp::INDEX.action_exist?("help")} == false
|
1343
|
+
ensure
|
1344
|
+
Benry::CmdApp::INDEX.register_action("help", ameta)
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
|
1351
|
+
topic '#do_teardown()' do
|
1352
|
+
|
1353
|
+
spec "[!zxeo7] clears '$cmdapp_config'." do
|
1354
|
+
$cmdapp_config = "AAA"
|
1355
|
+
@app.__send__(:do_teardown, nil)
|
1356
|
+
ok {$cmdapp_config} == nil
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
spec "[!ufm1d] clears '$cmdapp_application'." do
|
1360
|
+
$cmdapp_application = @app
|
1361
|
+
@app.__send__(:do_teardown, nil)
|
1362
|
+
ok {$cmdapp_application} == nil
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
|
1371
|
+
end
|