benry-cmdopt 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,197 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require_relative './shared'
5
+
6
+
7
+ Oktest.scope do
8
+
9
+
10
+ topic Benry::CmdOpt::Facade do
11
+
12
+
13
+ topic '#add()' do
14
+
15
+ spec "[!vmb3r] defines command option." do
16
+ cmdopt = Benry::CmdOpt.new()
17
+ cmdopt.add(:help, "-h, --help", "show help message", detail: "(text)", tag: :important)
18
+ items = cmdopt.instance_eval { @schema.instance_variable_get('@items') }
19
+ ok {items}.is_a?(Array)
20
+ ok {items.length} == 1
21
+ ok {items[0].key} == :help
22
+ ok {items[0].short} == 'h'
23
+ ok {items[0].long} == 'help'
24
+ ok {items[0].desc} == 'show help message'
25
+ ok {items[0].detail} == '(text)'
26
+ ok {items[0].tag} == :important
27
+ end
28
+
29
+ spec "[!71cvg] type, rexp, enum, and range are can be passed as positional args as well as keyword args." do
30
+ cmdopt = Benry::CmdOpt.new()
31
+ cmdopt.add(:key, "--optdef[=xx]", "desc", Integer, /\A\d+\z/, [2,4,8], (2..8), value: 4)
32
+ items = cmdopt.instance_eval { @schema.instance_variable_get('@items') }
33
+ item = items.first
34
+ ok {item.type} == Integer
35
+ ok {item.rexp} == /\A\d+\z/
36
+ ok {item.enum} == [2,4,8]
37
+ ok {item.range} == (2..8)
38
+ ok {item.value} == 4
39
+ end
40
+
41
+ spec "[!tu4k3] returns self." do
42
+ cmdopt = Benry::CmdOpt.new()
43
+ x = cmdopt.add(:version, "-v, --version", "version")
44
+ ok {x}.same?(cmdopt)
45
+ end
46
+
47
+ end
48
+
49
+
50
+ topic '#option_help()' do
51
+
52
+ before do
53
+ @cmdopt = Benry::CmdOpt.new
54
+ @cmdopt.add(:help , "-h, --help" , "show help message")
55
+ @cmdopt.add(:version, " --version" , "print version")
56
+ @cmdopt.add(:file , "-f, --file=<FILE>" , "filename")
57
+ end
58
+
59
+ spec "[!dm4p8] returns option help message." do
60
+ helpmsg = @cmdopt.option_help()
61
+ ok {helpmsg} == <<END
62
+ -h, --help : show help message
63
+ --version : print version
64
+ -f, --file=<FILE> : filename
65
+ END
66
+ end
67
+
68
+ end
69
+
70
+
71
+ topic '#to_s()' do
72
+
73
+ spec "[!s61vo] '#to_s' is an alias to '#option_help()'." do
74
+ cmdopt = Benry::CmdOpt.new
75
+ cmdopt.add(:help , "-h, --help" , "show help message")
76
+ cmdopt.add(:version, " --version" , "print version")
77
+ ok {cmdopt.to_s} == cmdopt.option_help()
78
+ end
79
+
80
+ end
81
+
82
+
83
+ topic '#each_option_and_desc()' do
84
+
85
+ before do
86
+ @cmdopt = Benry::CmdOpt.new
87
+ @cmdopt.add(:help , "-h, --help" , "show help message")
88
+ @cmdopt.add(:version, " --version" , "print version")
89
+ @cmdopt.add(:debug , "-D" , nil) # hidden option
90
+ @cmdopt.add(:trace , "-T" , "trace", hidden: true) # hidden option
91
+ end
92
+
93
+ spec "[!bw9qx] yields each option definition string and help message." do
94
+ pairs = []
95
+ @cmdopt.each_option_and_desc {|opt, desc| pairs << [opt, desc] }
96
+ ok {pairs} == [
97
+ ["-h, --help" , "show help message"],
98
+ [" --version", "print version"],
99
+ ]
100
+ end
101
+
102
+ spec "[!kunfw] yields all items (including hidden items) if `all: true` specified." do
103
+ ## when 'all: true'
104
+ pairs = []
105
+ @cmdopt.each_option_and_desc(all: true) {|opt, desc| pairs << [opt, desc] }
106
+ ok {pairs} == [
107
+ ["-h, --help" , "show help message"],
108
+ [" --version", "print version"],
109
+ ["-D" , nil],
110
+ ["-T" , "trace"],
111
+ ]
112
+ ## when 'all: false'
113
+ pairs = []
114
+ @cmdopt.each_option_and_desc(all: false) {|opt, desc| pairs << [opt, desc] }
115
+ ok {pairs} == [
116
+ ["-h, --help" , "show help message"],
117
+ [" --version", "print version"],
118
+ ]
119
+ end
120
+
121
+ spec "[!wght5] returns enumerator object if block not given." do
122
+ ## when 'all: true'
123
+ xs = @cmdopt.each_option_and_desc(all: true)
124
+ ok {xs}.is_a?(Enumerator)
125
+ ok {xs.collect {|x, _| x }} == ["-h, --help", " --version", "-D", "-T"]
126
+ ## when 'all: false'
127
+ xs = @cmdopt.each_option_and_desc(all: false)
128
+ ok {xs}.is_a?(Enumerator)
129
+ ok {xs.collect {|x, _| x }} == ["-h, --help", " --version"]
130
+ end
131
+
132
+ end
133
+
134
+
135
+ topic '#parse()' do
136
+
137
+ before do
138
+ @cmdopt = Benry::CmdOpt.new()
139
+ @cmdopt.add(:file, "-f, --file=<FILE>", "file") do |val|
140
+ File.open(val) {|f| f.read }
141
+ end
142
+ @cmdopt.add(:debug, "-d, --debug[=<LEVEL>]", "debug", type: Integer)
143
+ end
144
+
145
+ spec "[!7gc2m] parses command options." do
146
+ args = ["-d", "x", "y"]
147
+ @cmdopt.parse(args)
148
+ ok {args} == ["x", "y"]
149
+ end
150
+
151
+ spec "[!no4xu] returns option values as dict." do
152
+ args = ["-d", "x"]
153
+ ok {@cmdopt.parse(args)} == {:debug=>true}
154
+ end
155
+
156
+ spec "[!areof] handles only OptionError when block given." do
157
+ errmsg = nil
158
+ errcls = nil
159
+ @cmdopt.parse(["-dx"]) {|err|
160
+ errmsg = err.message
161
+ errcls = err.class
162
+ }
163
+ ok {errmsg} == "-dx: Integer expected."
164
+ ok {errcls} == Benry::CmdOpt::OptionError
165
+ #
166
+ pr = proc do
167
+ @cmdopt.parse(["-f", "/foo/bar/baz.png"])
168
+ end
169
+ ok {pr}.raise?(Errno::ENOENT, /No such file or directory/)
170
+ end
171
+
172
+ spec "[!peuva] returns nil when OptionError handled." do
173
+ ret = @cmdopt.parse(["-dx"]) {|err| 1 }
174
+ ok {ret} == nil
175
+ end
176
+
177
+ spec "[!za9at] parses options only before args when `all: false`." do
178
+ argv = ["aaa", "-d3", "bbb"]
179
+ #
180
+ argv1 = argv.dup
181
+ opts1 = @cmdopt.parse(argv1)
182
+ ok {opts1} == {:debug=>3}
183
+ ok {argv1} == ["aaa", "bbb"]
184
+ #
185
+ argv2 = argv.dup
186
+ opts2 = @cmdopt.parse(argv2, all: false)
187
+ ok {opts2} == {}
188
+ ok {argv2} == ["aaa", "-d3", "bbb"]
189
+ end
190
+
191
+ end
192
+
193
+
194
+ end
195
+
196
+
197
+ end
data/test/item_test.rb ADDED
@@ -0,0 +1,463 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require_relative './shared'
5
+
6
+
7
+ Oktest.scope do
8
+
9
+
10
+ topic Benry::CmdOpt::SchemaItem do
11
+
12
+ ITEMS = [
13
+ Benry::CmdOpt::SchemaItem.new(:help, "-h, --help", "help msg",
14
+ "h", "help", nil, nil),
15
+ Benry::CmdOpt::SchemaItem.new(:file, "-f, --file=<file>", "filename",
16
+ "f", "file", "<file>", true),
17
+ Benry::CmdOpt::SchemaItem.new(:indent, "-i, --indent[=<N>]", "indent width",
18
+ "i", "indent", "<N>", false),
19
+ ]
20
+
21
+
22
+ topic '#initialize()' do
23
+
24
+ before do
25
+ @schema = Benry::CmdOpt::Schema.new
26
+ end
27
+
28
+ spec "[!nn4cp] freezes enum object." do
29
+ item = Benry::CmdOpt::SchemaItem.new(:foo, "--foo", "desc", nil, "foo", "<val>",
30
+ true, enum: ["x", "y", "z"])
31
+ ok {item.enum} == ["x", "y", "z"]
32
+ ok {item.enum}.frozen?
33
+ end
34
+
35
+ case_when "[!wy2iv] when 'type:' specified..." do
36
+
37
+ spec "[!7xmr5] raises SchemaError when type is not registered." do
38
+ sc = @schema
39
+ pr = proc {
40
+ sc.add(:indent, "-i, --indent[=<WIDTH>]", "indent width", type: Array)
41
+ }
42
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
43
+ "Array: Unregistered type.")
44
+ end
45
+
46
+ spec "[!s2aaj] raises SchemaError when option has no params but type specified." do
47
+ sc = @schema
48
+ pr = proc {
49
+ sc.add(:indent, "-i, --indent", "indent width", type: Integer)
50
+ }
51
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
52
+ "Integer: Type specified in spite of option has no params.")
53
+ end
54
+
55
+ spec "[!sz8x2] not raise error when no params but value specified." do
56
+ sc = @schema
57
+ pr = proc {
58
+ sc.add(:indent, "-i, --indent", "indent width", type: Integer, value: 0)
59
+ }
60
+ ok {pr}.NOT.raise?(Exception)
61
+ end
62
+
63
+ spec "[!70ogf] not raise error when no params but TrueClass specified." do
64
+ sc = @schema
65
+ pr = proc {
66
+ sc.add(:indent, "-i, --indent", "indent width", type: TrueClass)
67
+ }
68
+ ok {pr}.NOT.raise?(Exception)
69
+ end
70
+
71
+ end
72
+
73
+ case_when "[!6y8s2] when 'rexp:' specified..." do
74
+
75
+ spec "[!bi2fh] raises SchemaError when pattern is not a regexp." do
76
+ sc = @schema
77
+ pr = proc {
78
+ sc.add(:indent, "-x, --indent[=<WIDTH>]", "indent width", rexp: '\A\d+\z')
79
+ }
80
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
81
+ '"\\\\A\\\\d+\\\\z": Regexp pattern expected.')
82
+ end
83
+
84
+ spec "[!01fmt] raises SchmeaError when option has no params but pattern specified." do
85
+ sc = @schema
86
+ pr = proc {
87
+ sc.add(:indent, "-i, --indent", "indent width", rexp: /\A\d+\z/)
88
+ }
89
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
90
+ '/\A\d+\z/: Regexp pattern specified in spite of option has no params.')
91
+ end
92
+
93
+ end
94
+
95
+ case_when "[!5nrvq] when 'enum:' specified..." do
96
+
97
+ spec "[!melyd] raises SchemaError when enum is not an Array nor Set." do
98
+ sc = @schema
99
+ sc.add(:indent1, "-i <N>", "indent width", enum: ["2", "4", "8"])
100
+ sc.add(:indent2, "-j <N>", "indent width", enum: Set.new(["2", "4", "8"]))
101
+ pr = proc {
102
+ sc.add(:indent3, "-k <N>", "indent width", enum: "2,4,8")
103
+ }
104
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
105
+ '"2,4,8": Array or set expected.')
106
+ end
107
+
108
+ spec "[!xqed8] raises SchemaError when enum specified for no param option." do
109
+ sc = @schema
110
+ pr = proc {
111
+ sc.add(:indent, "-i", "enable indent", enum: [2, 4, 8])
112
+ }
113
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
114
+ "[2, 4, 8]: Enum specified in spite of option has no params.")
115
+ end
116
+
117
+ spec "[!zuthh] raises SchemaError when enum element value is not instance of type class." do
118
+ sc = @schema
119
+ pr = proc {
120
+ sc.add(:indent, "-i <N>", "enable indent", type: Integer, enum: ['2', '4', '8'])
121
+ }
122
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
123
+ '["2", "4", "8"]: Enum element value should be instance of Integer, but "2" is not.')
124
+ end
125
+
126
+ end
127
+
128
+ case_when "[!hk4nw] when 'range:' specified..." do
129
+
130
+ spec "[!z20ky] raises SchemaError when range is not a Range object." do
131
+ pr = proc {
132
+ @schema.add(:indent, "-i <N>", "indent", type: Integer, range: [1,8])
133
+ }
134
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
135
+ "[1, 8]: Range object expected.")
136
+ end
137
+
138
+ spec "[!gp025] raises SchemaError when range specified with `type: TrueClass`." do
139
+ pr = proc {
140
+ @schema.add(:indent, "-i <N>", "indent", type: TrueClass, range: 0..1)
141
+ }
142
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
143
+ "0..1: Range is not available with `type: TrueClass`.")
144
+ end
145
+
146
+ spec "[!7njd5] range beginning/end value should be expected type." do
147
+ pr = proc {
148
+ @schema.add(:indent, "-i <N>", "indent", range: (1..8))
149
+ }
150
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
151
+ "1..8: Range value should be String, but not.")
152
+ pr = proc {
153
+ @schema.add(:indent, "-i <N>", "indent", type: Date, range: (1..8))
154
+ }
155
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
156
+ "1..8: Range value should be Date, but not.")
157
+ end
158
+
159
+ spec "[!uymig] range object can be endless." do
160
+ begin
161
+ range1 = eval "(1..)" # Ruby >= 2.6
162
+ range2 = eval "(..3)" # Ruby >= 2.6
163
+ rescue SyntaxError
164
+ range1 = nil # Ruby < 2.6
165
+ range2 = nil # Ruby < 2.6
166
+ end
167
+ if range1
168
+ pr = proc {
169
+ @schema.add(:indent1, "-i <N>", "indent", type: Integer, range: range1)
170
+ @schema.add(:indent2, "-j <N>", "indent", type: Integer, range: range2)
171
+ }
172
+ ok {pr}.NOT.raise?(Exception)
173
+ end
174
+ end
175
+
176
+ end
177
+
178
+ case_when "[!a0g52] when 'value:' specified..." do
179
+
180
+ spec "[!435t6] raises SchemaError when 'value:' is specified on argument-required option." do
181
+ sc = @schema
182
+ pr = proc {
183
+ sc.add(:flag, "--flag=<on|off>", "flag", type: TrueClass, value: true)
184
+ }
185
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
186
+ "true: 'value:' is meaningless when option has required argument (hint: change to optional argument instead).")
187
+ end
188
+
189
+ spec "[!6vwqv] raises SchemaError when type is TrueClass but value is not true nor false." do
190
+ sc = @schema
191
+ pr = proc {
192
+ sc.add(:flag, "--flag[=<on|off>]", "flag", type: TrueClass, value: 0)
193
+ }
194
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
195
+ "0: Value should be true or false when `type: TrueClass` specified.")
196
+ end
197
+
198
+ spec "[!c6i2o] raises SchemaError when value is not a kind of type." do
199
+ sc = @schema
200
+ pr = proc {
201
+ sc.add(:flag, "--flag[=<on|off>]", "flag", type: Integer, value: false)
202
+ }
203
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
204
+ "Type mismatched between `type: Integer` and `value: false`.")
205
+ end
206
+
207
+ spec "[!lnhp6] not raise error when type is not specified." do
208
+ sc = @schema
209
+ pr = proc {
210
+ sc.add(:flag, "--flag[=<on|off>]", "flag", value: false)
211
+ }
212
+ ok {pr}.NOT.raise?(Exception)
213
+ end
214
+
215
+ spec "[!6xb8o] value should be included in enum values." do
216
+ sc = @schema
217
+ pr = proc {
218
+ sc.add(:lang, "--lang[=<en|fr|it>]", "language", enum: ["en", "fr", "it"], value: "ja")
219
+ }
220
+ ok {pr}.raise?(Benry::CmdOpt::SchemaError,
221
+ "ja: Value should be included in enum values, but not.")
222
+ end
223
+
224
+ end
225
+
226
+ end
227
+
228
+
229
+ topic '#required?' do
230
+
231
+ spec "[!svxny] returns nil if option takes no arguments." do
232
+ item, _, _ = ITEMS
233
+ ok {item.required?} == nil
234
+ end
235
+
236
+ spec "[!togcx] returns true if argument is required." do
237
+ _, item, _ = ITEMS
238
+ ok {item.required?} == true
239
+ end
240
+
241
+ spec "[!uwbgc] returns false if argument is optional." do
242
+ _, _, item = ITEMS
243
+ ok {item.required?} == false
244
+ end
245
+
246
+ end
247
+
248
+
249
+ topic '#arg_requireness()' do
250
+
251
+ spec "[!kmo28] returns :none if option takes no arguments." do
252
+ item, _, _ = ITEMS
253
+ ok {item.arg_requireness()} == :none
254
+ end
255
+
256
+ spec "[!s8gxl] returns :required if argument is required." do
257
+ _, item, _ = ITEMS
258
+ ok {item.arg_requireness()} == :required
259
+ end
260
+
261
+ spec "[!owpba] returns :optional if argument is optional." do
262
+ _, _, item = ITEMS
263
+ ok {item.arg_requireness()} == :optional
264
+ end
265
+
266
+ end
267
+
268
+
269
+ topic '#multiple?()' do
270
+
271
+ spec "[!1lj8v] returns true if @multiple is truthy." do
272
+ item = Benry::CmdOpt::SchemaItem.new(:includes, "-I <path>", "include path", "I", nil, nil, nil, multiple: true)
273
+ ok {item.multiple?} == true
274
+ item = Benry::CmdOpt::SchemaItem.new(:includes, "-I <path>", "include path", "I", nil, nil, nil, multiple: 123)
275
+ ok {item.multiple?} == true
276
+ end
277
+
278
+ spec "[!cun23] returns false if @multiple is falthy." do
279
+ item = Benry::CmdOpt::SchemaItem.new(:includes, "-I <path>", "include path", "I", nil, nil, nil, multiple: false)
280
+ ok {item.multiple?} == false
281
+ item = Benry::CmdOpt::SchemaItem.new(:includes, "-I <path>", "include path", "I", nil, nil, nil, multiple: nil)
282
+ ok {item.multiple?} == false
283
+ end
284
+
285
+ end
286
+
287
+
288
+ topic '#hidden?()' do
289
+
290
+ spec "[!no6ov] returns true if @hidden is true." do
291
+ item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, hidden: true)
292
+ ok {item.hidden?} == true
293
+ end
294
+
295
+ spec "[!ej8ot] returns false if @hidden is false." do
296
+ item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, hidden: false)
297
+ ok {item.hidden?} == false
298
+ end
299
+
300
+ spec "[!h0uxs] returns true if desc is nil." do
301
+ desc = nil
302
+ item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", desc, "D", nil, nil, nil)
303
+ ok {item.hidden?} == true
304
+ end
305
+
306
+ spec "[!28vzx] returns false if else." do
307
+ desc = "debug mode"
308
+ item = Benry::CmdOpt::SchemaItem.new(:debug, "-D", desc, "D", nil, nil, nil)
309
+ ok {item.hidden?} == false
310
+ end
311
+
312
+ end
313
+
314
+
315
+ topic '#important?()' do
316
+
317
+ spec "[!ua8kt] returns true/false if `important:` kwarg passed to constructor." do
318
+ item1 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, important: true)
319
+ ok {item1.important?} == true
320
+ item2 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil, important: false)
321
+ ok {item2.important?} == false
322
+ end
323
+
324
+ spec "[!hz9sx] returns nil if `important:` kwarg not passed to constructor." do
325
+ item3 = Benry::CmdOpt::SchemaItem.new(:debug, "-D", "debug mode", "D", nil, nil, nil)
326
+ ok {item3.important?} == nil
327
+ end
328
+
329
+ end
330
+
331
+
332
+ topic '#validate_and_convert()' do
333
+
334
+ def new_item(key, optstr, desc, short, long, param, required,
335
+ type: nil, rexp: nil, enum: nil, range: nil, value: nil, &callback)
336
+ return Benry::CmdOpt::SchemaItem.new(key, optstr, desc, short, long, param, required,
337
+ type: type, rexp: rexp, enum: enum, range: range, value: value, &callback)
338
+ end
339
+
340
+ spec "[!h0s0o] raises RuntimeError when value not matched to pattern." do
341
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, rexp: /\A\d+\z/)
342
+ optdict = {}
343
+ pr = proc { x.validate_and_convert("abc", optdict) }
344
+ ok {pr}.raise?(RuntimeError, "Pattern unmatched.")
345
+ end
346
+
347
+ spec "[!5jrdf] raises RuntimeError when value not in enum." do
348
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, enum: ['2', '4', '8'])
349
+ optdict = {}
350
+ pr = proc { x.validate_and_convert("10", optdict) }
351
+ ok {pr}.raise?(RuntimeError, "Expected one of 2/4/8.")
352
+ end
353
+
354
+ spec "[!5falp] raise RuntimeError when value not in range." do
355
+ x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
356
+ type: Integer, range: 2..8)
357
+ optdict = {}
358
+ pr = proc { x.validate_and_convert("1", optdict) }
359
+ ok {pr}.raise?(RuntimeError, "Too small (min: 2)")
360
+ pr = proc { x.validate_and_convert("9", optdict) }
361
+ ok {pr}.raise?(RuntimeError, "Too large (max: 8)")
362
+ ## when min==0
363
+ x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
364
+ type: Integer, range: 0..8)
365
+ optdict = {}
366
+ pr = proc { x.validate_and_convert("-1", optdict) }
367
+ ok {pr}.raise?(RuntimeError, "Positive value (>= 0) expected.")
368
+ ## when min==1
369
+ x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
370
+ type: Integer, range: 1..8)
371
+ optdict = {}
372
+ pr = proc { x.validate_and_convert("0", optdict) }
373
+ ok {pr}.raise?(RuntimeError, "Positive value (>= 1) expected.")
374
+ end
375
+
376
+ spec "[!a0rej] supports endless range." do
377
+ begin
378
+ range1 = eval "(2..)" # Ruby >= 2.6
379
+ range2 = eval "(..8)"
380
+ rescue SyntaxError
381
+ range1 = nil # Ruby < 2.6
382
+ range2 = nil
383
+ end
384
+ if range1
385
+ x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
386
+ type: Integer, range: range1)
387
+ optdict = {}
388
+ pr = proc { x.validate_and_convert("1", optdict) }
389
+ ok {pr}.raise?(RuntimeError, "Too small (min: 2)")
390
+ pr = proc { x.validate_and_convert("9", optdict) }
391
+ ok {pr}.NOT.raise?(RuntimeError)
392
+ end
393
+ if range2
394
+ x = new_item(:indent, "-i[=<N>]", "indent", "i", nil, "<N>", false,
395
+ type: Integer, range: range2)
396
+ optdict = {}
397
+ pr = proc { x.validate_and_convert("1", optdict) }
398
+ ok {pr}.NOT.raise?(RuntimeError)
399
+ pr = proc { x.validate_and_convert("9", optdict) }
400
+ ok {pr}.raise?(RuntimeError, "Too large (max: 8)")
401
+ end
402
+ end
403
+
404
+ spec "[!j4fuz] calls type-specific callback when type specified." do
405
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer)
406
+ optdict = {}
407
+ pr = proc { x.validate_and_convert("abc", optdict) }
408
+ ok {pr}.raise?(RuntimeError, "Integer expected.")
409
+ end
410
+
411
+ spec "[!jn9z3] calls callback when callback specified." do
412
+ called = false
413
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|va|
414
+ called = true
415
+ }
416
+ optdict = {}
417
+ x.validate_and_convert("abc", optdict)
418
+ ok {called} == true
419
+ end
420
+
421
+ spec "[!iqalh] calls callback with different number of args according to arity." do
422
+ args1 = nil
423
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|val|
424
+ args1 = val
425
+ }
426
+ optdict = {}
427
+ x.validate_and_convert("123", optdict)
428
+ ok {args1} == "123"
429
+ #
430
+ args2 = nil
431
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false) {|optdict, key, val|
432
+ args2 = [optdict, key, val]
433
+ }
434
+ optdict = {}
435
+ x.validate_and_convert("123", optdict)
436
+ ok {args2} == [optdict, :indent, "123"]
437
+ end
438
+
439
+ spec "[!x066l] returns new value." do
440
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer)
441
+ ok {x.validate_and_convert("123", {})} == 123
442
+ #
443
+ x = new_item(:indent, "", "indent width", "i", "indent", "<WIDTH>", false, type: Integer) {|val|
444
+ val * 2
445
+ }
446
+ ok {x.validate_and_convert("123", {})} == 246
447
+ end
448
+
449
+ spec "[!eafem] returns default value (if specified) instead of true value." do
450
+ x1 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: nil)
451
+ ok {x1.validate_and_convert(true, {})} == true
452
+ x2 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: "blabla")
453
+ ok {x2.validate_and_convert(true, {})} == "blabla"
454
+ x3 = new_item(:flag, "", "desc", "f", "flag", nil, false, value: false)
455
+ ok {x3.validate_and_convert(true, {})} == false
456
+ end
457
+
458
+ end
459
+
460
+ end
461
+
462
+
463
+ end