benry-cmdapp 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/test/app_test.rb CHANGED
@@ -1,1365 +1,1169 @@
1
1
  # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
2
3
 
3
- require 'oktest'
4
4
 
5
- require 'benry/cmdapp'
6
- require_relative './shared'
5
+ require_relative 'shared'
7
6
 
8
7
 
9
8
  Oktest.scope do
10
9
 
11
10
 
11
+ topic Benry::CmdApp::Application do
12
12
 
13
- topic Benry::CmdApp::Config do
13
+ before do
14
+ @config = Benry::CmdApp::Config.new("test app", "1.2.3", app_command: "testapp")
15
+ @app = Benry::CmdApp::Application.new(@config)
16
+ end
14
17
 
15
18
 
16
- topic '#initialize()' do
19
+ topic '#main()' do
17
20
 
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)
21
+ spec "[!65e9n] returns `0` as status code." do
22
+ ret = nil
23
+ capture_sio { ret = @app.main(["help"]) }
24
+ ok {ret} == 0
22
25
  end
23
26
 
24
- end
25
-
27
+ case_when "[!bkbb4] when error raised..." do
26
28
 
27
- end
29
+ spec "[!k4qov] not catch error if debug mode is enabled." do
30
+ debug_mode = $DEBUG_MODE
31
+ at_end { $DEBUG_MODE = debug_mode }
32
+ pr = proc { @app.main(["--debug", "foobar"]) }
33
+ ok {pr}.raise?(Benry::CmdApp::CommandError, "foobar: Action not found.")
34
+ end
28
35
 
36
+ spec "[!lhlff] catches error if BaseError raised or `should_rescue?()` returns true." do
37
+ pr = proc { @app.main(["testerr1"]) }
38
+ ok {pr}.raise?(ZeroDivisionError)
39
+ #
40
+ r = recorder()
41
+ r.fake_method(@app, :should_rescue? => true)
42
+ sout, serr = capture_sio(tty: true) do
43
+ pr = proc { @app.main(["testerr1"]) }
44
+ ok {pr}.NOT.raise?(ZeroDivisionError)
45
+ end
46
+ ok {sout} == ""
47
+ ok {serr} =~ /\A\e\[31m\[ERROR\]\e\[0m divided by 0$/
48
+ end
29
49
 
30
- topic Benry::CmdApp::AppOptionSchema do
50
+ spec "[!35x5p] prints error into stderr." do
51
+ sout, serr = capture_sio(tty: true) { @app.main(["foobar"]) }
52
+ ok {sout} == ""
53
+ ok {serr} =~ /^\e\[31m\[ERROR\]\e\[0m foobar: Action not found.\n/
54
+ end
31
55
 
56
+ spec "[!z39bh] prints backtrace unless error is a CommandError." do
57
+ sout, serr = capture_sio { @app.main(["testerr2"]) }
58
+ ok {sout} == ""
59
+ ok {serr} =~ /^\[ERROR\] testerr2: Looped action detected.\n/
60
+ ok {serr} =~ /^ From .*:\d+:in /
61
+ end
32
62
 
33
- topic '#initialize()' do
63
+ spec "[!dzept] returns `1` as status code." do
64
+ ret = nil
65
+ capture_sio { ret = @app.main(["help", "foo"]) }
66
+ ok {ret} == 1
67
+ end
34
68
 
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
69
  end
40
70
 
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
71
+ end
47
72
 
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
73
 
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
74
+ topic '#run()' do
65
75
 
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
76
+ spec "[!etbbc] calls setup method at beginning of this method." do
77
+ r = recorder()
78
+ r.record_method(@app, :setup)
79
+ capture_sio { @app.run("help") }
80
+ ok {r[0].name} == :setup
81
+ ok {r[0].args} == []
73
82
  end
74
83
 
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
84
+ spec "[!hguvb] handles global options." do
85
+ sout, serr = capture_sio { @app.run("--version") }
86
+ ok {sout} == "1.2.3\n"
87
+ ok {serr} == ""
88
+ sout, serr = capture_sio { @app.run("--help") }
89
+ ok {sout} =~ /^Usage:\n/
90
+ ok {serr} == ""
82
91
  end
83
92
 
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
93
+ spec "[!pf1d2] calls teardown method at end of this method." do
94
+ r = recorder()
95
+ r.record_method(@app, :teardown)
96
+ capture_sio { @app.run("hello", "Alice") }
97
+ ok {r.length} == 1
98
+ ok {r[0].name} == :teardown
99
+ ok {r[0].args} == []
100
+ #
101
+ begin
102
+ capture_sio { @app.run("testerr1") }
103
+ rescue ZeroDivisionError
104
+ nil
105
+ end
106
+ ok {r.length} == 2
107
+ ok {r[0].name} == :teardown
108
+ ok {r[0].args} == []
91
109
  end
92
110
 
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
111
+ end
99
112
 
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
113
 
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
114
+ topic '#handle_action()' do
117
115
 
118
- end
116
+ case_when "[!3qw3p] when no arguments specified..." do
119
117
 
118
+ spec "[!zl9em] lists actions if default action is not set." do
119
+ sout, serr = capture_sio { @app.run() }
120
+ ok {sout} =~ /\AActions:\n/
121
+ ok {sout} =~ /^ hello +: greeting message$/
122
+ ok {serr} == ""
123
+ end
120
124
 
121
- topic '#sort_options_in_this_order()' do
125
+ spec "[!89hqb] lists all actions including hidden ones if `-a` or `--all` specified." do
126
+ sout, serr = capture_sio { @app.run() }
127
+ ok {sout} !~ /^ debuginfo/
128
+ sout, serr = capture_sio { @app.run("-a") }
129
+ ok {sout} =~ /^ debuginfo +: hidden action$/
130
+ end
122
131
 
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
132
+ spec "[!k4xxp] runs default action if it is set." do
133
+ @config.default_action = "hello"
134
+ sout, serr = capture_sio { @app.run() }
135
+ ok {sout} !~ /^\AActions:/
136
+ ok {sout} == "Hello, world!\n"
137
+ end
131
138
 
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
139
  end
140
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
141
+ case_when "[!xaamy] when prefix specified..." do
149
142
 
150
- end
143
+ spec "[!7l3fh] lists actions starting with prefix." do
144
+ sout, serr = capture_sio { @app.run("git:") }
145
+ ok {sout} == <<END
146
+ Actions:
147
+ git:stage : same as `git add -p`
148
+ git:staged : same as `git diff --cached`
149
+ git:unstage : same as `git reset HEAD`
150
+ END
151
+ end
151
152
 
153
+ spec "[!g0k1g] lists all actions including hidden ones if `-a` or `--all` specified." do
154
+ sout, serr = capture_sio { @app.run("-a", "git:") }
155
+ ok {sout} == <<END
156
+ Actions:
157
+ git:correct : same as `git commit --amend`
158
+ git:stage : same as `git add -p`
159
+ git:staged : same as `git diff --cached`
160
+ git:unstage : same as `git reset HEAD`
161
+ END
162
+ end
152
163
 
153
- end
164
+ end
154
165
 
166
+ case_when "[!vphz3] else..." do
155
167
 
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
+ spec "[!bq39a] runs action with arguments." do
169
+ sout, serr = capture_sio { @app.run("hello", "Alice") }
170
+ ok {sout} == "Hello, Alice!\n"
171
+ end
172
+
173
+ spec "[!5yd8x] returns 0 when action invoked successfully." do
174
+ ret = nil
175
+ capture_sio { ret = @app.run("hello", "Alice") }
176
+ ok {ret} == 0
168
177
  end
178
+
169
179
  end
170
- end
171
180
 
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
181
  end
179
182
 
180
- def _run_app(*args)
181
- sout, serr = capture_sio { @app.run(*args) }
182
- ok {serr} == ""
183
- return sout
184
- end
185
183
 
184
+ topic '#render_help_message()' do
186
185
 
187
- topic '#initialize()' do
186
+ spec "[!2oax5] returns action help message if action name is specified." do
187
+ ret = @app.render_help_message("hello")
188
+ ok {ret} == <<"END"
189
+ \e[1mtestapp hello\e[0m --- greeting message
188
190
 
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)
191
+ \e[1;34mUsage:\e[0m
192
+ $ \e[1mtestapp hello\e[0m [<options>] [<name>]
193
+
194
+ \e[1;34mOptions:\e[0m
195
+ -l, --lang=<lang> : language name (en/fr/it)
202
196
  END
203
197
  end
204
198
 
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
199
+ spec "[!d6veb] returns application help message if action name is not specified." do
200
+ ret = @app.render_help_message(nil)
201
+ ok {ret} =~ /^\e\[1;34mUsage:\e\[0m$/
202
+ ok {ret} =~ /^\e\[1;34mOptions:\e\[0m$/
203
+ ok {ret} =~ /^\e\[1;34mActions:\e\[0m$/
204
+ end
205
+
206
+ spec "[!tf2wp] includes hidden actions and options into help message if `all: true` passed." do
207
+ rexp1 = /^\e\[2m --debug : debug mode\e\[0m/
208
+ rexp2 = /^\e\[2m debuginfo : hidden action\e\[0m/
209
+ #
210
+ s = @app.render_help_message(nil, all: true)
211
+ ok {s} =~ rexp1
212
+ ok {s} =~ rexp2
213
+ #
214
+ s = @app.render_help_message(nil, all: false)
215
+ ok {s} !~ rexp1
216
+ ok {s} !~ rexp2
217
217
  end
218
218
 
219
219
  end
220
220
 
221
221
 
222
- topic '#main()' do
222
+ topic '#setup()' do
223
223
 
224
- after do
225
- $cmdapp_config = nil
224
+ spec "[!6hi1y] stores current application." do
225
+ at_end { Benry::CmdApp._set_current_app(nil) }
226
+ ok {Benry::CmdApp.current_app()} == nil
227
+ @app.__send__(:setup)
228
+ ok {Benry::CmdApp.current_app()} == @app
226
229
  end
227
230
 
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
231
+ end
233
232
 
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
233
 
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
234
+ topic '#teardown()' do
262
235
 
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/
236
+ spec "[!t44mv] removes current applicatin from data store." do
237
+ at_end { Benry::CmdApp._set_current_app(nil) }
238
+ ok {Benry::CmdApp.current_app()} == nil
239
+ @app.__send__(:setup)
240
+ ok {Benry::CmdApp.current_app()} == @app
291
241
  end
292
242
 
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
243
+ end
303
244
 
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
245
 
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} == ""
246
+ topic '#parse_global_options()' do
247
+
248
+ spec "[!9c9r8] parses global options." do
249
+ args = ["-hl", "foo"]
250
+ opts = @app.instance_eval { parse_global_options(args) }
251
+ ok {opts} == {help: true, list: true}
252
+ ok {args} == ["foo"]
322
253
  end
323
254
 
324
255
  end
325
256
 
326
257
 
327
- topic '#run()' do
258
+ topic '#toggle_global_options()' do
328
259
 
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
260
+ spec "[!xwcyl] sets `$VERBOSE_MODE` and `$QUIET_MODE` according to global options." do
261
+ at_end { $VERBOSE_MODE = nil; $QUIET_MODE = nil }
350
262
  #
351
- @action.("arity test with variable args")
352
- def test_arity2(xx, yy, zz=nil, *rest)
353
- end
263
+ opts = {verbose: true}
264
+ @app.instance_eval { toggle_global_options(opts) }
265
+ ok {$VERBOSE_MODE} == true
266
+ ok {$QUIET_MODE} == false
354
267
  #
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
268
+ opts = {quiet: true}
269
+ @app.instance_eval { toggle_global_options(opts) }
270
+ ok {$VERBOSE_MODE} == false
271
+ ok {$QUIET_MODE} == true
368
272
  end
369
273
 
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"
274
+ spec "[!sucqp] sets `$DEBUG_MODE` according to global options." do
275
+ at_end { $DEBUG_MODE = nil }
276
+ opts = {debug: true}
277
+ @app.instance_eval { toggle_global_options(opts) }
278
+ ok {$DEBUG_MODE} == true
374
279
  end
375
280
 
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}
281
+ spec "[!510eb] sets `$COLOR_MODE` according to global option." do
282
+ bkup = $COLOR_MODE
283
+ at_end { $COLOR_MODE = bkup }
284
+ $COLOR_MODE = nil
285
+ #
286
+ opts = {color: true}
287
+ @app.instance_eval { toggle_global_options(opts) }
288
+ ok {$COLOR_MODE} == true
289
+ #
290
+ opts = {color: false}
291
+ @app.instance_eval { toggle_global_options(opts) }
292
+ ok {$COLOR_MODE} == false
380
293
  end
381
294
 
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
295
+ spec "[!y9fow] sets `config.trace_mode` if global option specified." do
296
+ opts = {trace: true}
297
+ @app.instance_eval { toggle_global_options(opts) }
298
+ ok {@config.trace_mode} == true
299
+ #
300
+ opts = {trace: false}
301
+ @app.instance_eval { toggle_global_options(opts) }
302
+ ok {@config.trace_mode} == false
422
303
  end
423
304
 
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"]
305
+ spec "[!dply7] sets `$DRYRUN_MODE` according to global option." do
306
+ ok {$DRYRUN_MODE} == nil
307
+ at_end { $DRYRUN_MODE = nil }
308
+ #
309
+ opts = {dryrun: true}
310
+ @app.instance_eval { toggle_global_options(opts) }
311
+ ok {$DRYRUN_MODE} == true
434
312
  end
435
313
 
436
- spec "[!w584g] calls callback method." do
437
- def @app.do_callback(args, global_opts)
438
- @_called_ = args.dup
314
+ end
315
+
316
+
317
+ topic '#handle_global_options()' do
318
+
319
+ spec "[!366kv] prints help message if global option `-h, --help` specified." do
320
+ opts = {help: true}
321
+ sout, serr = capture_sio do
322
+ @app.instance_eval { handle_global_options(opts, []) }
439
323
  end
440
- ok {@app.instance_variable_get('@_called_')} == nil
441
- capture_sio { @app.run("sayhello") }
442
- ok {@app.instance_variable_get('@_called_')} == ["sayhello"]
324
+ ok {sout} =~ /^Usage:/
325
+ ok {sout} =~ /^Options:/
326
+ ok {sout} =~ /^Actions:/
443
327
  end
444
328
 
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
329
+ spec "[!7mapy] includes hidden actions into help message if `-a, --all` specified." do
330
+ rexp1 = /^ --debug : debug mode$/
331
+ rexp2 = /^ debuginfo : hidden action$/
332
+ #
333
+ opts = {help: true}
334
+ sout, serr = capture_sio do
335
+ @app.instance_eval { handle_global_options(opts, []) }
453
336
  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
337
+ ok {sout} !~ rexp1
338
+ ok {sout} !~ rexp2
339
+ #
340
+ opts = {help: true, all: true}
341
+ sout, serr = capture_sio do
342
+ @app.instance_eval { handle_global_options(opts, []) }
468
343
  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
344
+ ok {sout} =~ rexp1
345
+ ok {sout} =~ rexp2
485
346
  end
486
347
 
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
348
+ spec "[!dkjw8] prints version number if global option `-V, --version` specified." do
349
+ opts = {version: true}
350
+ sout, serr = capture_sio do
351
+ @app.instance_eval { handle_global_options(opts, []) }
494
352
  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
353
+ ok {sout} == "1.2.3\n"
509
354
  end
510
355
 
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
356
+ spec "[!hj4hf] prints action and alias list if global option `-l, --list` specified." do
357
+ opts = {list: true}
358
+ sout, serr = capture_sio(tty: true) do
359
+ @app.instance_eval { handle_global_options(opts, []) }
517
360
  end
518
- def @app.do_run_action(metadata, args, global_opts)
519
- ret = super
520
- @_args2 = args.dup
521
- ret
361
+ ok {sout} =~ /\A\e\[1;34mActions:\e\[0m$/
362
+ if Benry::CmdApp::REGISTRY.metadata_each.any? {|md| md.alias? }
363
+ ok {sout} =~ /\n\n\e\[1;34mAliases:\e\[0m$/
364
+ else
365
+ ok {sout} !~ /Aliases:/
522
366
  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
367
  end
529
368
 
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:/
369
+ spec "[!tyxwo] includes hidden actions into action list if `-a, --all` specified." do
370
+ rexp = /^ debuginfo +: hidden action$/
560
371
  #
561
- @config.default_help = true
562
- sout, serr = capture_sio { @app.run() }
563
- ok {serr} == ""
564
- ok {sout} == expected
372
+ opts = {list: true}
373
+ sout, serr = capture_sio do
374
+ @app.instance_eval { handle_global_options(opts, []) }
375
+ end
376
+ ok {sout} !~ rexp
377
+ #
378
+ opts = {list: true, all: true}
379
+ sout, serr = capture_sio do
380
+ @app.instance_eval { handle_global_options(opts, []) }
381
+ end
382
+ ok {sout} =~ rexp
565
383
  end
566
384
 
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).")
385
+ spec "[!ooiaf] prints topic list if global option '-L <topic>' specified." do
386
+ Benry::CmdApp.define_alias('h0053', 'hello')
387
+ Benry::CmdApp.define_abbrev('g0053:', 'git:')
388
+ at_end {
389
+ Benry::CmdApp.undef_alias('h0053')
390
+ #Benry::CmdApp.undef_abbrev('g0053:')
391
+ Benry::CmdApp::REGISTRY.instance_eval { @abbrev_dict.delete('g0053:') }
392
+ }
393
+ #
394
+ chead = '\e\[1;34mCategories:\e\[0m'
395
+ data = [
396
+ [/\A\e\[1;34mActions:\e\[0m$/ , ["action" , "actions" ]],
397
+ [/\A\e\[1;34mAliases:\e\[0m$/ , ["alias" , "aliases" ]],
398
+ [/\A\e\[1;34mAbbreviations:\e\[0m$/ , ["abbrev" , "abbrevs" ]],
399
+ [/\A#{chead} \e\[2m\(depth=0\)\e\[0m$/, ["category" , "categories" ]],
400
+ [/\A#{chead} \e\[2m\(depth=1\)\e\[0m$/, ["category1", "categories1"]],
401
+ [/\A#{chead} \e\[2m\(depth=2\)\e\[0m$/, ["category2", "categories2"]],
402
+ [/\A#{chead} \e\[2m\(depth=3\)\e\[0m$/, ["category3", "categories3"]],
403
+ ]
404
+ data.each do |rexp, topics|
405
+ topics.each do |topic|
406
+ g_opts = {topic: topic}
407
+ sout, serr = capture_sio(tty: true) do
408
+ @app.instance_eval { handle_global_options(g_opts, []) }
409
+ end
410
+ ok {sout} =~ rexp
411
+ end
412
+ end
572
413
  end
573
414
 
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
415
+ spec "[!ymifi] includes hidden actions into topic list if `-a, --all` specified." do
416
+ g_opts = {topic: "action", all: true}
417
+ sout, serr = capture_sio do
418
+ @app.instance_eval { handle_global_options(g_opts, []) }
583
419
  end
420
+ ok {sout} =~ /\AActions:$/
421
+ ok {sout} =~ /^ debuginfo : hidden action$/
584
422
  end
585
423
 
586
- spec "[!wv22u] calls teardown method at end of running action." do
587
- def @app.do_teardown(*args)
588
- @_args = args
424
+ spec "[!k31ry] returns `0` if help or version or actions printed." do
425
+ keys = [:help, :version, :list]
426
+ keys.each do |key|
427
+ ret = nil
428
+ opts = {key => true}
429
+ capture_sio do
430
+ ret = @app.instance_eval { handle_global_options(opts, []) }
431
+ end
432
+ ok {ret} == 0
589
433
  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
434
  end
594
435
 
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]
436
+ spec "[!9agnb] returns `nil` if do nothing." do
437
+ ret = nil
438
+ opts = {color: true, debug: true}
439
+ capture_sio do
440
+ ret = @app.instance_eval { handle_global_options(opts, []) }
603
441
  end
442
+ ok {ret} == nil
604
443
  end
605
444
 
606
445
  end
607
446
 
608
447
 
609
- topic '#help_message()' do
448
+ topic '#render_action_help()' do
610
449
 
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
450
+ spec "[!c510c] returns action help message." do
451
+ s = @app.instance_eval { render_action_help("hello") }
452
+ ok {s} == <<"END"
453
+ \e[1mtestapp hello\e[0m --- greeting message
616
454
 
617
- Usage:
618
- $ testapp [<options>] [<action> [<arguments>...]]
455
+ \e[1;34mUsage:\e[0m
456
+ $ \e[1mtestapp hello\e[0m [<options>] [<name>]
619
457
 
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:
458
+ \e[1;34mOptions:\e[0m
459
+ -l, --lang=<lang> : language name (en/fr/it)
627
460
  END
628
461
  end
629
462
 
630
463
  end
631
464
 
632
465
 
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
466
+ topic '#render_application_help()' do
646
467
 
647
- end
468
+ spec "[!iyxxb] returns application help message." do
469
+ actual = @app.instance_eval { render_application_help() }
470
+ expected = <<"END"
471
+ \e[1mtestapp\e[0m \e[2m(1.2.3)\e[0m --- test app
648
472
 
473
+ \e[1;34mUsage:\e[0m
474
+ $ \e[1mtestapp\e[0m [<options>] <action> [<arguments>...]
649
475
 
650
- topic '#do_create_help_message_builder()' do
476
+ \e[1;34mOptions:\e[0m
477
+ -h, --help : print help message (of action if specified)
478
+ -V, --version : print version
479
+ -l, --list : list actions and aliases
480
+ -a, --all : list hidden actions/options, too
651
481
 
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)
482
+ \e[1;34mActions:\e[0m
483
+ END
484
+ ok {actual}.start_with?(expected)
485
+ ok {actual} =~ /^ hello : greeting message$/
486
+ ok {actual} =~ /^ git:stage : same as `git add -p`$/
658
487
  end
659
488
 
660
489
  end
661
490
 
662
491
 
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
492
+ topic '#render_version()' do
670
493
 
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.")
494
+ spec "[!bcp2g] returns version number string." do
495
+ s = @app.instance_eval { render_version() }
496
+ ok {s} == "1.2.3\n"
674
497
  end
675
498
 
676
499
  end
677
500
 
678
501
 
679
- topic '#do_toggle_global_switches()' do
502
+ topic '#render_item_list()' do
680
503
 
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)
504
+ class FakeAppHelpBuilder < Benry::CmdApp::ApplicationHelpBuilder
505
+ def section_availables(include=true, all: false); return nil; end
506
+ def section_candidates(prefix, all: false); return nil; end
507
+ def section_categories(depth=1, all: false); return nil; end
689
508
  end
690
509
 
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
510
+ def fake_app_help_builder(&b)
511
+ Benry::CmdApp.module_eval do
512
+ remove_const :APPLICATION_HELP_BUILDER_CLASS
513
+ const_set :APPLICATION_HELP_BUILDER_CLASS, FakeAppHelpBuilder
514
+ end
515
+ yield
516
+ ensure
517
+ Benry::CmdApp.module_eval do
518
+ remove_const :APPLICATION_HELP_BUILDER_CLASS
519
+ const_set :APPLICATION_HELP_BUILDER_CLASS, Benry::CmdApp::ApplicationHelpBuilder
702
520
  end
703
521
  end
704
522
 
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
523
+ case_when "[!tftl5] when prefix is not specified..." do
524
+
525
+ spec "[!36vz6] returns action list string if any actions defined." do
526
+ s = @app.instance_eval { render_item_list(nil) }
527
+ ok {s} !~ /\A\e\[1;34mUsage:\e\[0m$/
528
+ ok {s} !~ /\A\e\[1;34mOptions:\e\[0m$/
529
+ ok {s} =~ /\A\e\[1;34mActions:\e\[0m$/
716
530
  end
717
- end
718
531
 
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
532
+ spec "[!znuy4] raises CommandError if no actions defined." do
533
+ fake_app_help_builder() do
534
+ pr = proc { @app.instance_eval { render_item_list(nil) } }
535
+ ok {pr}.raise?(Benry::CmdApp::CommandError,
536
+ "No actions defined.")
727
537
  end
728
- ensure
729
- $COLOR_MODE = bkup
730
538
  end
539
+
731
540
  end
732
541
 
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
542
+ case_when "[!jcq4z] when separator is specified..." do
543
+
544
+ spec "[!w1j1e] returns top prefix list if ':' specified." do
545
+ s = @app.instance_eval { render_item_list(":") }
546
+ ok {s} !~ /\A\e\[1;34mUsage:\e\[0m$/
547
+ ok {s} !~ /\A\e\[1;34mOptions:\e\[0m$/
548
+ ok {s} !~ /\A\e\[1;34mActions:\e\[0m$/
549
+ ok {s} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=\d+\)\e\[0m$/
550
+ #
551
+ ok {s} !~ /^ hello/
552
+ #ok {s} =~ /^ foo: \(\d+\)$/
553
+ ok {s} =~ /^ git: \(\d+\)$/
554
+ ok {s} =~ /^ giit: \(\d+\)/
555
+ ok {s} !~ /^ hello/
556
+ #
557
+ ok {s} =~ /^ giit: \(\d\d\) : gitt commands$/
558
+ ok {s} !~ /^ giit:branch: \(\d+\)$/
559
+ ok {s} !~ /^ giit:commit: \(\d+\)$/
560
+ ok {s} !~ /^ giit:repo: \(\d+\)$/
561
+ ok {s} !~ /^ giit:staging: \(\d+\)$/
745
562
  end
746
- end
747
563
 
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
564
+ spec "[!bgput] returns two depth prefix list if '::' specified." do
565
+ s = @app.instance_eval { render_item_list("::") }
566
+ ok {s} !~ /\A\e\[1;34mUsage:\e\[0m$/
567
+ ok {s} !~ /\A\e\[1;34mOptions:\e\[0m$/
568
+ ok {s} !~ /\A\e\[1;34mActions:\e\[0m$/
569
+ ok {s} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=\d+\)\e\[0m$/
570
+ #
571
+ #ok {s} =~ /^ foo: \(\d+\)$/
572
+ ok {s} =~ /^ git: \(\d+\)$/
573
+ ok {s} =~ /^ giit: \(\d\) : gitt commands$/
574
+ ok {s} !~ /^ hello/
575
+ #
576
+ ok {s} =~ /^ giit:branch: \(\d+\)$/
577
+ ok {s} =~ /^ giit:commit: \(\d+\)$/
578
+ ok {s} =~ /^ giit:repo: \(\d+\)$/
579
+ ok {s} =~ /^ giit:staging: \(\d+\)$/
580
+ end
581
+
582
+ spec "[!tiihg] raises CommandError if no actions found having prefix." do
583
+ fake_app_help_builder() do
584
+ pr = proc { @app.instance_eval { render_item_list(":") } }
585
+ ok {pr}.raise?(Benry::CmdApp::CommandError,
586
+ "Prefix of actions not found.")
756
587
  end
757
- ensure
758
- $TRACE_MODE = bkup
759
588
  end
589
+
760
590
  end
761
591
 
762
- end
592
+ case_when "[!xut9o] when prefix is specified..." do
763
593
 
594
+ spec "[!z4dqn] filters action list by prefix if specified." do
595
+ s = @app.instance_eval { render_item_list("git:") }
596
+ ok {s} == <<"END"
597
+ \e[1;34mActions:\e[0m
598
+ git:stage : same as `git add -p`
599
+ git:staged : same as `git diff --cached`
600
+ git:unstage : same as `git reset HEAD`
601
+ END
602
+ end
764
603
 
765
- topic '#do_handle_global_options()' do
604
+ spec "[!1834c] raises CommandError if no actions found with names starting with that prefix." do
605
+ fake_app_help_builder() do
606
+ pr = proc { @app.instance_eval { render_item_list("git:") } }
607
+ ok {pr}.raise?(Benry::CmdApp::CommandError,
608
+ "No actions found with names starting with 'git:'.")
609
+ end
610
+ end
766
611
 
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
612
  end
781
613
 
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>...]]
614
+ case_else "[!xjdrm] else..." do
788
615
 
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)
616
+ spec "[!9r4w9] raises ArgumentError." do
617
+ pr = proc { @app.instance_eval { render_item_list("git") } }
618
+ ok {pr}.raise?(ArgumentError,
619
+ "\"git\": Invalid value as a prefix.")
805
620
  end
621
+
806
622
  end
807
623
 
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
624
+ end
811
625
 
812
- Usage:
813
- $ testapp sayhello [<options>] [<user>]
814
626
 
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
627
+ topic '#render_topic_list()' do
825
628
 
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
629
+ spec "[!uzmml] renders topic list." do
630
+ x = @app.__send__(:render_topic_list, "action")
631
+ ok {x} =~ /\A\e\[1;34mActions:\e\[0m$/
632
+ ok {x} =~ /^ hello : greeting message$/
633
+ #
634
+ Benry::CmdApp.define_alias("chiaou", ["hello", "-l", "it"])
635
+ x = @app.__send__(:render_topic_list, "alias")
636
+ ok {x} =~ /\A\e\[1;34mAliases:\e\[0m$/
637
+ ok {x} =~ /^ chiaou : alias for 'hello -l it'$/
638
+ #
639
+ x = @app.__send__(:render_topic_list, "category")
640
+ ok {x} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=0\)\e\[0m$/
641
+ ok {x} =~ /^ git: \(3\)$/
642
+ ok {x} =~ /^ giit: \(\d+\) +: gitt commands$/
643
+ #
644
+ Benry::CmdApp.define_abbrev("g31:", "git:")
645
+ x = @app.__send__(:render_topic_list, "abbrev")
646
+ ok {x} =~ /\A\e\[1;34mAbbreviations:\e\[0m$/
647
+ ok {x} =~ /^ g31: +=> git:$/
648
+ end
649
+
650
+ spec "[!vrzu0] topic 'category1' or 'categories2' is acceptable." do
651
+ x = @app.__send__(:render_topic_list, "category1")
652
+ ok {x} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=1\)\e\[0m$/
653
+ ok {x} =~ /^ git: \(3\)$/
654
+ ok {x} =~ /^ giit: \(\d+\) +: gitt commands$/
655
+ ok {x} !~ /^ giit:branch:/
656
+ ok {x} !~ /^ giit:repo:/
657
+ #
658
+ x = @app.__send__(:render_topic_list, "category2")
659
+ ok {x} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=2\)\e\[0m$/
660
+ ok {x} =~ /^ git: \(3\)$/
661
+ ok {x} =~ /^ giit: \(0\) +: gitt commands$/
662
+ ok {x} =~ /^ giit:branch: \(2\)$/
663
+ ok {x} =~ /^ giit:repo: \(7\)$/
664
+ ok {x} !~ /^ giit:repo:config:/
665
+ ok {x} !~ /^ giit:repo:remote:/
666
+ #
667
+ x = @app.__send__(:render_topic_list, "categories3")
668
+ ok {x} =~ /\A\e\[1;34mCategories:\e\[0m \e\[2m\(depth=3\)\e\[0m$/
669
+ ok {x} =~ /^ git: \(3\)$/
670
+ ok {x} =~ /^ giit: \(0\) +: gitt commands$/
671
+ ok {x} =~ /^ giit:branch: \(2\)$/
672
+ ok {x} =~ /^ giit:repo: \(2\)$/
673
+ ok {x} =~ /^ giit:repo:config: \(3\)$/
674
+ ok {x} =~ /^ giit:repo:remote: \(2\)$/
675
+ end
676
+
677
+ spec "[!xyn5g] global option '-L metadata' renders registry data in YAML format." do
678
+ config = Benry::CmdApp::Config.new("test app", "0.0.0")
679
+ app = Benry::CmdApp::Application.new(config)
680
+ sout, serr = capture_sio { app.run("-L", "metadata") }
681
+ ok {serr} == ""
682
+ require 'yaml'
683
+ ydoc = YAML.load(sout)
684
+ ok {ydoc["actions"]}.is_a?(Array)
685
+ ok {ydoc["aliases"]}.is_a?(Array)
686
+ ok {ydoc["categories"]}.is_a?(Array)
687
+ ok {ydoc["abbreviations"]}.is_a?(Array)
833
688
  end
834
689
 
835
690
  end
836
691
 
837
692
 
838
- topic '#do_callback()' do
693
+ topic '#handle_blank_action()' do
839
694
 
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
695
+ spec "[!seba7] prints action list and returns `0`." do
696
+ ret = nil
697
+ sout, serr = capture_sio do
698
+ ret = @app.instance_eval { handle_blank_action() }
862
699
  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
700
+ ok {sout} !~ /\AUsage:$/
701
+ ok {sout} !~ /\AOptions:$/
702
+ ok {sout} =~ /\AActions:$/
703
+ ok {ret} == 0
870
704
  end
871
705
 
872
706
  end
873
707
 
874
708
 
875
- topic '#do_find_action()' do
709
+ topic '#handle_prefix()' do
876
710
 
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"
711
+ spec "[!8w301] prints action list starting with prefix and returns `0`." do
712
+ ret = nil
713
+ sout, serr = capture_sio do
714
+ ret = @app.instance_eval { handle_prefix("git:") }
715
+ end
716
+ ok {ret} == 0
717
+ ok {sout} == <<"END"
718
+ Actions:
719
+ git:stage : same as `git add -p`
720
+ git:staged : same as `git diff --cached`
721
+ git:unstage : same as `git reset HEAD`
722
+ END
881
723
  end
882
724
 
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
725
+ end
888
726
 
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
727
 
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
728
+ topic '#start_action()' do
902
729
 
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
730
+ spec "[!vbymd] runs action with args and returns `0`." do
731
+ ret = nil
732
+ sout, serr = capture_sio do
733
+ ret = @app.instance_eval { start_action("hello", ["-l", "it", "Alice"]) }
734
+ end
735
+ ok {ret} == 0
736
+ ok {sout} == "Chao, Alice!\n"
908
737
  end
909
738
 
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).")
739
+ spec "[!6htva] supports abbreviation of prefix." do
740
+ Benry::CmdApp.define_abbrev("g1:", "git:")
741
+ sout, serr = capture_sio do
742
+ @app.instance_eval do
743
+ start_action("g1:stage", ["."])
744
+ start_action("g1:unstage", [])
745
+ end
746
+ end
747
+ ok {sout} == <<'END'
748
+ git add -p .
749
+ git reset HEAD
750
+ END
916
751
  end
917
752
 
918
753
  end
919
754
 
920
755
 
921
- topic '#do_run_action()' do
756
+ topic '#new_context()' do
922
757
 
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"
758
+ spec "[!9ddcl] creates new context object with config object." do
759
+ x = @app.instance_eval { new_context() }
760
+ ok {x}.is_a?(Benry::CmdApp::ApplicationContext)
761
+ ok {x.instance_variable_get(:@config)} == @config
927
762
  end
928
763
 
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
764
+ end
934
765
 
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
766
 
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
767
+ topic '#print_str()' do
946
768
 
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)
769
+ spec "[!yiabh] do nothing if str is nil." do
770
+ sout, serr = capture_sio do
771
+ @app.instance_eval { print_str nil }
772
+ end
773
+ ok {sout} == ""
774
+ ok {serr} == ""
952
775
  end
953
776
 
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"
777
+ spec "[!6kyv9] prints string as is if color mode is enabled." do
778
+ bkup = $COLOR_MODE; at_end { $COLOR_MODE = bkup }
779
+ $COLOR_MODE = true
780
+ sout, serr = capture_sio do
781
+ @app.instance_eval { print_str("\e[1mHello\e[0m") }
782
+ end
783
+ ok {sout} == "\e[1mHello\e[0m"
958
784
  end
959
785
 
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.")
786
+ spec "[!lxhvq] deletes escape characters from string and prints it if color mode is disabled." do
787
+ bkup = $COLOR_MODE; at_end { $COLOR_MODE = bkup }
788
+ $COLOR_MODE = false
789
+ sout, serr = capture_sio do
790
+ @app.instance_eval { print_str("\e[1mHello\e[0m") }
791
+ end
792
+ ok {sout} == "Hello"
964
793
  end
965
794
 
966
795
  end
967
796
 
968
797
 
969
- topic '#do_print_help_message()' do
798
+ topic '#print_error()' do
970
799
 
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
800
+ fixture(:err) {
801
+ begin
802
+ 1/0
803
+ rescue ZeroDivisionError => err
804
+ end
805
+ err
806
+ }
976
807
 
977
- Usage:
978
- $ testapp sayhello [<options>] [<user>]
808
+ spec "[!sdbj8] prints exception as error message." do |err|
809
+ sout, serr = capture_sio(tty: true) do
810
+ @app.instance_eval { print_error(err) }
811
+ end
812
+ ok {sout} == ""
813
+ ok {serr} == "\e[31m[ERROR]\e[0m divided by 0\n"
814
+ end
979
815
 
980
- Options:
981
- -l, --lang=<en|fr|it> : language
982
- END
816
+ spec "[!6z0mu] prints colored error message if stderr is a tty." do |err|
817
+ sout, serr = capture_sio(tty: true) do
818
+ @app.instance_eval { print_error(err) }
819
+ end
820
+ ok {sout} == ""
821
+ ok {serr} == "\e[31m[ERROR]\e[0m divided by 0\n"
983
822
  end
984
823
 
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.")
824
+ spec "[!k1s3o] prints non-colored error message if stderr is not a tty." do |err|
825
+ sout, serr = capture_sio(tty: false) do
826
+ @app.instance_eval { print_error(err) }
990
827
  end
828
+ ok {sout} == ""
829
+ ok {serr} == "[ERROR] divided by 0\n"
991
830
  end
992
831
 
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
832
+ end
998
833
 
999
- Usage:
1000
- $ testapp [<options>] [<action> [<arguments>...]]
1001
834
 
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)
835
+ topic '#print_backtrace()' do
1007
836
 
1008
- Actions:
1009
- END
1010
- end
837
+ fixture(:err) {
838
+ begin
839
+ 1/0
840
+ rescue ZeroDivisionError => err
841
+ end
842
+ err
843
+ }
1011
844
 
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", hidden: true)
1017
- def hidden1(trace: false)
1018
- end
845
+ spec "[!i010e] skips backtrace in `benry/cmdapp.rb`." do |err|
846
+ sout, serr = capture_sio() do
847
+ @app.instance_eval { print_backtrace(err) }
1019
848
  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$/
849
+ ok {sout} == ""
850
+ ok {serr} !~ /benry\/cmdapp\.rb/
851
+ ok {serr} =~ /app_test\.rb/
1028
852
  end
1029
853
 
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
854
+ spec "[!ilaxg] skips backtrace if `#skip_backtrace?()` returns truthy value." do |err|
855
+ sout1, serr1 = capture_sio() do
856
+ @app.instance_eval { print_backtrace(err) }
1036
857
  end
1037
- msg = without_tty { app.run("-h") }
1038
- ok {app.instance_variable_get('@_all_')} != nil
1039
- ok {app.instance_variable_get('@_all_')} == false
858
+ ok {serr1} =~ /app_test\.rb/
1040
859
  #
1041
- msg = without_tty { app.run("-ha") }
1042
- ok {app.instance_variable_get('@_all_')} != nil
1043
- ok {app.instance_variable_get('@_all_')} == true
860
+ r = recorder()
861
+ r.fake_method(@app, :'skip_backtrace?' => true)
862
+ sout2, serr2 = capture_sio() do
863
+ @app.instance_eval { print_backtrace(err) }
864
+ end
865
+ ok {serr2} == ""
1044
866
  end
1045
867
 
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
868
+ spec "[!5sa5k] prints filename and line number in slant format if stdout is a tty." do |err|
869
+ sout, serr = capture_sio(tty: true) do
870
+ @app.instance_eval { print_backtrace(err) }
871
+ end
872
+ ok {sout} == ""
873
+ ok {serr} =~ /\A \e\[3mFrom test\/app_test\.rb:\d+:in `\/'\e\[0m/
1061
874
  end
1062
875
 
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:
876
+ spec "[!2sg9r] not to try to read file content if file not found." do |err|
877
+ newbt = [
878
+ "#{__FILE__}:#{__LINE__}:in `foo`",
879
+ "-e:#{__LINE__}:in `bar`",
880
+ "#{__FILE__}:#{__LINE__}:in `baz`",
881
+ ]
882
+ n = __LINE__ - 4 # base lineno
883
+ err.set_backtrace(newbt)
884
+ sout, serr = capture_sio(tty: true) do
885
+ @app.instance_eval { print_backtrace(err) }
886
+ end
887
+ ok {sout} == ""
888
+ ok {serr} == <<"END"
889
+ \e[3mFrom test/app_test.rb:#{n+0}:in `foo`\e[0m
890
+ "\#{__FILE__}:\#{__LINE__}:in `foo`",
891
+ \e[3mFrom -e:#{n+1}:in `bar`\e[0m
892
+ \e[3mFrom test/app_test.rb:#{n+2}:in `baz`\e[0m
893
+ "\#{__FILE__}:\#{__LINE__}:in `baz`",
1077
894
  END
1078
895
  end
1079
896
 
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
897
+ spec "[!ihizf] prints lines of each backtrace entry." do |err|
898
+ sout, serr = capture_sio(tty: true) do
899
+ @app.instance_eval { print_backtrace(err) }
1101
900
  end
901
+ ok {sout} == ""
902
+ ok {serr} =~ /^ 1\/0\n/
1102
903
  end
1103
904
 
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
905
+ spec "[!8wzxg] prints backtrace of exception." do |err|
906
+ sout, serr = capture_sio() do
907
+ @app.instance_eval { print_backtrace(err) }
1125
908
  end
909
+ ok {sout} == ""
910
+ ok {serr} =~ /\A From test\/app_test\.rb:\d+:in `\/'\n 1\/0\n/
1126
911
  end
1127
912
 
1128
913
  end
1129
914
 
1130
915
 
1131
- topic '#do_validate_actions()' do
916
+ topic '#skip_backtrace?()' do
1132
917
 
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
918
+ spec "[!r2fmv] ignores backtraces if matched to 'config.backtrace_ignore_rexp'." do
919
+ @config.backtrace_ignore_rexp = /\/foobar\.rb/
920
+ bt1 = "/home/yourname/foobar.rb:123:"
921
+ bt2 = "/home/yourname/blabla.rb:123:"
922
+ _ = self
923
+ @app.instance_eval do
924
+ _.ok {skip_backtrace?(bt1)} == 14
925
+ _.ok {skip_backtrace?(bt2)} == nil
1138
926
  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'
927
+ end
1144
928
 
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 }
929
+ spec "[!c6f11] not ignore backtraces if 'config.backtrace_ignore_rexp' is not set." do
930
+ @config.backtrace_ignore_rexp = nil
931
+ bt1 = "/home/yourname/foobar.rb:123:"
932
+ bt2 = "/home/yourname/blabla.rb:123:"
933
+ _ = self
934
+ @app.instance_eval do
935
+ _.ok {skip_backtrace?(bt1)} == false
936
+ _.ok {skip_backtrace?(bt2)} == false
1150
937
  end
1151
938
  end
1152
939
 
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'
940
+ end
1162
941
 
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
942
 
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'
943
+ topic '#read_file_as_lines()' do
1179
944
 
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
945
+ spec "[!e9c74] reads file content as an array of line." do
946
+ lines = @app.instance_eval { read_file_as_lines(__FILE__) }
947
+ ok {lines}.is_a?(Array)
948
+ ok {lines[__LINE__ - 2]} == " ok {lines}.is_a?(Array)\n"
1185
949
  end
1186
950
 
1187
951
  end
1188
952
 
1189
953
 
1190
- topic '#do_print_candidates()' do
954
+ topic '#should_rescue?()' do
1191
955
 
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
956
+ spec "[!8lwyn] returns trueif exception is a BaseError." do
957
+ x = @app.__send__(:should_rescue?, Benry::CmdApp::DefinitionError.new)
958
+ ok {x} == true
959
+ x = @app.__send__(:should_rescue?, RuntimeError.new)
960
+ ok {x} == false
1212
961
  end
1213
962
 
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
963
+ end
1241
964
 
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
965
 
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)
966
+ end
967
+
968
+
969
+ topic Benry::CmdApp::GlobalOptionSchema do
970
+
971
+ def new_schema(config)
972
+ return Benry::CmdApp::GlobalOptionSchema.new(config)
973
+ end
974
+
975
+
976
+ topic '#initialize()' do
977
+
978
+ spec "[!ppcvp] adds options according to config object." do
979
+ config = Benry::CmdApp::Config.new("sample app", "1.2.3")
980
+ schema = new_schema(config)
981
+ ok {schema.get(:help)} != nil
982
+ ok {schema.get(:version)} != nil
983
+ ok {schema.get(:list)} != nil
984
+ ok {schema.get(:all)} != nil
985
+ ok {schema.get(:verbose)} == nil
986
+ ok {schema.get(:quiet)} == nil
987
+ ok {schema.get(:color)} == nil
988
+ ok {schema.get(:debug)} != nil
989
+ ok {schema.get(:debug)}.hidden?
990
+ ok {schema.to_s} == <<"END"
991
+ -h, --help : print help message (of action if specified)
992
+ -V, --version : print version
993
+ -l, --list : list actions and aliases
994
+ -a, --all : list hidden actions/options, too
995
+ END
996
+ ok {schema.get(:trace)} == nil
997
+ #
998
+ config.option_help = false
999
+ config.option_version = false
1000
+ config.option_list = false
1001
+ config.option_all = false
1002
+ config.option_verbose = true
1003
+ config.option_quiet = true
1004
+ config.option_color = true
1005
+ config.option_debug = true
1006
+ config.option_trace = true
1007
+ #
1008
+ schema = new_schema(config)
1009
+ ok {schema.get(:help)} == nil
1010
+ ok {schema.get(:version)} == nil
1011
+ ok {schema.get(:list)} == nil
1012
+ ok {schema.get(:all)} == nil
1013
+ ok {schema.get(:verbose)} != nil
1014
+ ok {schema.get(:quiet)} != nil
1015
+ ok {schema.get(:color)} != nil
1016
+ ok {schema.get(:trace)} != nil
1017
+ ok {schema.get(:debug)}.NOT.hidden?
1018
+ end
1019
+
1020
+ spec "[!doj0k] if config option is `:hidden`, makes option as hidden." do
1021
+ config = Benry::CmdApp::Config.new("sample app", "1.2.3")
1022
+ config.option_help = :hidden
1023
+ config.option_version = :hidden
1024
+ config.option_list = :hidden
1025
+ config.option_topic = :hidden
1026
+ config.option_all = :hidden
1027
+ config.option_verbose = :hidden
1028
+ config.option_quiet = :hidden
1029
+ config.option_color = :hidden
1030
+ config.option_debug = :hidden
1031
+ config.option_trace = :hidden
1032
+ #
1033
+ schema = new_schema(config)
1034
+ ok {schema.get(:help ).hidden?} == true
1035
+ ok {schema.get(:version).hidden?} == true
1036
+ ok {schema.get(:list ).hidden?} == true
1037
+ ok {schema.get(:topic ).hidden?} == true
1038
+ ok {schema.get(:all ).hidden?} == true
1039
+ ok {schema.get(:verbose).hidden?} == true
1040
+ ok {schema.get(:quiet ).hidden?} == true
1041
+ ok {schema.get(:color ).hidden?} == true
1042
+ ok {schema.get(:debug ).hidden?} == true
1043
+ ok {schema.get(:trace ).hidden?} == true
1044
+ #
1045
+ ok {schema.option_help()} == ""
1046
+ ok {schema.option_help(all: true)} == <<'END'
1047
+ --help : print help message (of action if specified)
1048
+ --version : print version
1049
+ --list : list actions and aliases
1050
+ -L <topic> : topic list (actions|aliases|categories|abbrevs)
1051
+ --all : list hidden actions/options, too
1052
+ --verbose : verbose mode
1053
+ --quiet : quiet mode
1054
+ --color[=<on|off>] : color mode
1055
+ --debug : debug mode
1056
+ --trace : trace mode
1292
1057
  END
1293
1058
  end
1294
1059
 
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
1060
+ spec "[!umjw5] add nothing if config is nil." do
1061
+ schema = new_schema(nil)
1062
+ ok {schema}.empty?
1315
1063
  end
1316
1064
 
1317
1065
  end
1318
1066
 
1319
1067
 
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
1068
+ topic '#reorder_options(*keys)' do
1328
1069
 
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
1070
+ spec "[!2cp9s] sorts options in order of keys specified." do
1071
+ config = Benry::CmdApp::Config.new("sample app", "1.2.3", option_debug: true)
1072
+ schema = new_schema(config)
1073
+ ok {schema.to_s} == <<'END'
1074
+ -h, --help : print help message (of action if specified)
1075
+ -V, --version : print version
1076
+ -l, --list : list actions and aliases
1077
+ -a, --all : list hidden actions/options, too
1078
+ --debug : debug mode
1079
+ END
1080
+ #
1081
+ schema.reorder_options(:list, :topic, :help, :all, :debug, :version)
1082
+ ok {schema.to_s} == <<'END'
1083
+ -l, --list : list actions and aliases
1084
+ -h, --help : print help message (of action if specified)
1085
+ -a, --all : list hidden actions/options, too
1086
+ --debug : debug mode
1087
+ -V, --version : print version
1088
+ END
1334
1089
  end
1335
1090
 
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
1091
+ spec "[!xe7e1] moves options which are not included in specified keys to end of option list." do
1092
+ config = Benry::CmdApp::Config.new("sample app", "1.2.3", option_debug: true)
1093
+ schema = new_schema(config)
1094
+ schema.reorder_options(:list, :help)
1095
+ ok {schema.to_s} == <<'END'
1096
+ -l, --list : list actions and aliases
1097
+ -h, --help : print help message (of action if specified)
1098
+ -V, --version : print version
1099
+ -a, --all : list hidden actions/options, too
1100
+ --debug : debug mode
1101
+ END
1346
1102
  end
1347
1103
 
1348
1104
  end
1349
1105
 
1350
1106
 
1351
- topic '#do_teardown()' do
1107
+ end
1352
1108
 
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
1109
 
1359
- spec "[!ufm1d] clears '$cmdapp_application'." do
1360
- $cmdapp_application = @app
1361
- @app.__send__(:do_teardown, nil)
1362
- ok {$cmdapp_application} == nil
1110
+ topic Benry::CmdApp::MetadataRenderer do
1111
+
1112
+
1113
+ topic '#render_metadata()' do
1114
+
1115
+ before do
1116
+ reg = Benry::CmdApp::REGISTRY
1117
+ @registry = Benry::CmdApp::Registry.new
1118
+ r = @registry
1119
+ r.metadata_add(reg.metadata_get("hello"))
1120
+ r.metadata_add(Benry::CmdApp::AliasMetadata.new("hi", "hello", []))
1121
+ r.category_add("cat:", "test category")
1122
+ r.abbrev_add("c:", "cat:")
1123
+ end
1124
+
1125
+ EXPECTED = <<'END'
1126
+ actions:
1127
+ - action: hello
1128
+ desc: "greeting message"
1129
+ class: MyAction
1130
+ method: hello
1131
+ hidden: false
1132
+ paramstr: "[<name>]"
1133
+ parameters:
1134
+ - param: name
1135
+ type: opt
1136
+ - param: lang
1137
+ type: key
1138
+ options:
1139
+ - key: lang
1140
+ desc: "language name (en/fr/it)"
1141
+ optdef: "-l, --lang=<lang>"
1142
+ short: l
1143
+ long: lang
1144
+ param: "<lang>"
1145
+ paramreq: required
1146
+ hidden: false
1147
+
1148
+ aliases:
1149
+ - alias: hi
1150
+ desc: "alias for 'hello'"
1151
+ action: hello
1152
+
1153
+ categories:
1154
+ - prefix: "cat:"
1155
+ count: 0
1156
+ desc: "test category"
1157
+
1158
+ abbreviations:
1159
+ - abbrev: "c:"
1160
+ prefix: "cat:"
1161
+ END
1162
+
1163
+ spec "[!gduge] renders registry data in YAML format." do
1164
+ renderer = Benry::CmdApp::MetadataRenderer.new(@registry)
1165
+ yaml = renderer.render_metadata()
1166
+ ok {yaml} == EXPECTED
1363
1167
  end
1364
1168
 
1365
1169
  end