v / vlib / flag / flag_test.v
671 lines · 609 sloc · 18.71 KB · bf1ec742725658f1f22bbf8af7943daae411fd58
Raw
1import flag
2
3fn test_if_flag_not_given_return_default_values() {
4 mut fp := flag.new_flag_parser([])
5 assert false == fp.bool('a_bool', 0, false, '')
6 assert 42 == fp.int('an_int', 0, 42, '')
7 assert 1.0 == fp.float('a_float', 0, 1.0, '')
8 assert 'stuff' == fp.string('a_string', 0, 'stuff', '')
9}
10
11fn test_if_flag_not_given_can_return_option_defaults() {
12 mut fp := flag.new_flag_parser([])
13 assert fp.bool_val('a_bool', 0, ?bool(none), '') == none
14 assert fp.int_val('an_int', 0, ?int(none), '') == none
15 assert fp.float_val('a_float', 0, ?f64(none), '') == none
16 assert fp.string_val('a_string', 0, ?string(none), '') == none
17}
18
19fn test_if_flag_not_given_preserves_typed_option_defaults() {
20 mut fp := flag.new_flag_parser([])
21 a_bool := fp.bool_val('a_bool', 0, ?bool(true), '')
22 an_int := fp.int_val('an_int', 0, ?int(42), '')
23 a_float := fp.float_val('a_float', 0, ?f64(1.5), '')
24 a_string := fp.string_val('a_string', 0, ?string('stuff'), '')
25 if value := a_bool {
26 assert value
27 } else {
28 assert false
29 }
30 if value := an_int {
31 assert value == 42
32 } else {
33 assert false
34 }
35 if value := a_float {
36 assert value == 1.5
37 } else {
38 assert false
39 }
40 if value := a_string {
41 assert value == 'stuff'
42 } else {
43 assert false
44 }
45}
46
47fn test_could_define_application_name_and_version() {
48 mut fp := flag.new_flag_parser([])
49 fp.application('test app')
50 fp.version('0.0.42')
51 fp.description('some text')
52 assert fp.application_name == 'test app'
53 assert fp.application_version == '0.0.42'
54 assert fp.application_description == 'some text'
55}
56
57fn test_bool_flags_do_not_need_an_value() {
58 mut fp := flag.new_flag_parser(['--a_bool'])
59 assert true == fp.bool('a_bool', 0, false, '')
60}
61
62fn test_flag_values_can_be_returned_as_options() {
63 mut fp := flag.new_flag_parser([
64 '--an_int',
65 '42',
66 '--a_float=2.0',
67 '--a_string',
68 'stuff',
69 '--a_bool=false',
70 ])
71 a_bool := fp.bool_val('a_bool', 0, ?bool(none), '')
72 an_int := fp.int_val('an_int', 0, ?int(none), '')
73 a_float := fp.float_val('a_float', 0, ?f64(none), '')
74 a_string := fp.string_val('a_string', 0, ?string(none), '')
75 if value := a_bool {
76 assert !value
77 } else {
78 assert false
79 }
80 if value := an_int {
81 assert value == 42
82 } else {
83 assert false
84 }
85 if value := a_float {
86 assert value == 2.0
87 } else {
88 assert false
89 }
90 if value := a_string {
91 assert value == 'stuff'
92 } else {
93 assert false
94 }
95}
96
97fn test_flags_could_be_defined_with_eq() {
98 mut fp := flag.new_flag_parser([
99 '--an_int=42',
100 '--a_float=2.0',
101 '--bool_without',
102 '--a_string=stuff',
103 '--a_bool=true',
104 ])
105 assert 42 == fp.int('an_int', 0, 0o666, '')
106 assert true == fp.bool('a_bool', 0, false, '')
107 assert true == fp.bool('bool_without', 0, false, '')
108 assert 2.0 == fp.float('a_float', 0, 1.0, '')
109 assert 'stuff' == fp.string('a_string', 0, 'not_stuff', '')
110}
111
112fn test_values_could_be_defined_without_eq() {
113 mut fp := flag.new_flag_parser([
114 '--an_int',
115 '42',
116 '--a_float',
117 '2.0',
118 '--bool_without',
119 '--a_string',
120 'stuff',
121 '--a_bool',
122 'true',
123 ])
124 assert 42 == fp.int('an_int', 0, 0o666, '')
125 assert true == fp.bool('a_bool', 0, false, '')
126 assert true == fp.bool('bool_without', 0, false, '')
127 assert 2.0 == fp.float('a_float', 0, 1.0, '')
128 assert 'stuff' == fp.string('a_string', 0, 'not_stuff', '')
129}
130
131fn test_values_could_be_defined_mixed() {
132 mut fp := flag.new_flag_parser([
133 '--an_int',
134 '42',
135 '--a_float=2.0',
136 '--bool_without',
137 '--a_string',
138 'stuff',
139 '--a_bool=true',
140 ])
141 assert 42 == fp.int('an_int', 0, 0o666, '')
142 assert true == fp.bool('a_bool', 0, false, '')
143 assert true == fp.bool('bool_without', 0, false, '')
144 assert 2.0 == fp.float('a_float', 0, 1.0, '')
145 assert 'stuff' == fp.string('a_string', 0, 'not_stuff', '')
146}
147
148fn test_beaware_for_argument_names_with_same_prefix() {
149 mut fp := flag.new_flag_parser([
150 '--short',
151 '5',
152 '--shorter=7',
153 ])
154 assert 5 == fp.int('short', 0, 0o666, '')
155 assert 7 == fp.int('shorter', 0, 0o666, '')
156}
157
158fn test_beaware_for_argument_names_with_same_prefix_inverse() {
159 mut fp := flag.new_flag_parser([
160 '--shorter=7',
161 '--short',
162 '5',
163 ])
164 assert 5 == fp.int('short', 0, 0o666, '')
165 assert 7 == fp.int('shorter', 0, 0o666, '')
166}
167
168fn test_allow_to_skip_executable_path() {
169 mut fp := flag.new_flag_parser(['./path/to/execuable'])
170 fp.skip_executable()
171 args := fp.finalize() or {
172 assert false
173 return
174 }
175 assert !args.contains('./path/to/execuable')
176}
177
178fn test_none_flag_arguments_are_allowed() {
179 mut fp := flag.new_flag_parser([
180 'file1',
181 '--an_int=2',
182 'file2',
183 'file3',
184 '--bool_without',
185 'file4',
186 '--outfile',
187 'outfile',
188 ])
189 assert 2 == fp.int('an_int', 0, 0o666, '')
190 assert 'outfile' == fp.string('outfile', 0, 'bad', '')
191 assert true == fp.bool('bool_without', 0, false, '')
192}
193
194fn test_finalize_returns_none_flag_arguments_ordered() {
195 mut fp := flag.new_flag_parser(['d', 'b', 'x', 'a', '--outfile', 'outfile'])
196 fp.string('outfile', 0, 'bad', '')
197 finalized := fp.finalize() or {
198 assert false
199 return
200 }
201 expected := ['d', 'b', 'x', 'a']
202 for i, v in finalized {
203 assert v == expected[i]
204 }
205}
206
207fn test_finalize_returns_error_for_unknown_flags_long() {
208 mut fp := flag.new_flag_parser(['--known', '--unknown'])
209 fp.bool('known', 0, false, '')
210 finalized := fp.finalize() or {
211 assert err.msg() == 'Unknown flag `--unknown`'
212 return
213 }
214 assert finalized.len < 0 // expect error to be returned
215}
216
217fn test_finalize_returns_error_for_unknown_flags_short() {
218 mut fp := flag.new_flag_parser(['--known', '-x'])
219 fp.bool('known', 0, false, '')
220 finalized := fp.finalize() or {
221 assert err.msg() == 'Unknown flag `-x`'
222 return
223 }
224 assert finalized.len < 0 // expect error to be returned
225}
226
227fn test_allow_to_build_usage_message() {
228 mut fp := flag.new_flag_parser([])
229 fp.limit_free_args(1, 4)!
230 fp.application('flag_tool')
231 fp.version('v0.0.0')
232 fp.description('some short information about this tool')
233 fp.int('an_int', 0, 0o666, 'some int to define')
234 fp.bool('a_bool', 0, false, 'some bool to define')
235 fp.bool('bool_without_but_really_big', 0, false, 'this should appear on the next line')
236 fp.float('a_float', 0, 1.0, 'some float as well')
237 fp.string('a_string', 0, 'not_stuff', 'your credit card number')
238 usage := fp.usage()
239 mut all_strings_found := true
240 for s in ['flag_tool', 'v0.0.0', 'an_int <int>', 'a_bool', 'bool_without', 'a_float <float>',
241 'a_string <string>', 'some int to define', 'some bool to define',
242 'this should appear on the next line', 'some float as well', 'your credit card number',
243 'The arguments should be at least 1 and at most 4 in number.', 'Usage', 'Options:',
244 'Description:', 'some short information about this tool'] {
245 if !usage.contains(s) {
246 eprintln(" missing '${s}' in usage message")
247 all_strings_found = false
248 }
249 }
250 assert all_strings_found
251}
252
253fn test_usage_shows_default_values_for_defaulted_options() {
254 mut fp := flag.new_flag_parser([])
255 fp.int('count', `c`, 34, 'My parameter')
256 fp.float('ratio', `r`, 1.25, 'My ratio')
257 fp.string('name', `n`, 'guest', 'My name')
258 fp.string('empty', 0, '', 'Empty string')
259 fp.bool('verbose', `v`, false, 'Be chatty')
260 usage := fp.usage()
261 assert usage.contains('My parameter (default 34)')
262 assert usage.contains('My ratio (default 1.25)')
263 assert usage.contains('My name (default "guest")')
264 assert usage.contains('Empty string (default "")')
265 assert usage.contains('Be chatty (default false)')
266}
267
268fn test_builtin_flags_do_not_show_default_values_in_usage() {
269 mut fp := flag.new_flag_parser([])
270 fp.finalize() or { panic(err) }
271 usage := fp.usage()
272 assert !usage.contains('display this help and exit (default false)')
273 assert !usage.contains('output version information and exit (default false)')
274}
275
276fn test_if_app_name_given_but_no_show_usage_message_still_contain_version() {
277 mut fp := flag.new_flag_parser([])
278 fp.application('flag_tool')
279 fp.version('v0.0.0')
280 fp.description('a description')
281 fp.bool('a_bool', 0, false, '')
282 fp.options.show.clear(.name)
283 assert fp.usage().contains('v0.0.0\n---')
284}
285
286fn test_if_version_given_but_no_show_usage_message_does_not_contain_banner() {
287 mut fp := flag.new_flag_parser([])
288 fp.application('flag_tool')
289 fp.version('v0.0.0')
290 fp.description('a description')
291 fp.bool('a_bool', 0, false, '')
292 fp.options.show.clear(.version)
293 assert !fp.usage().contains('v0.0.0\n---')
294}
295
296fn test_if_no_description_given_usage_message_does_not_contain_description() {
297 mut fp := flag.new_flag_parser([])
298 fp.application('flag_tool')
299 fp.version('v0.0.0')
300 fp.bool('a_bool', 0, false, '')
301 assert !fp.usage().contains('Description:')
302}
303
304fn test_if_description_given_but_no_show_usage_message_does_not_contain_description() {
305 mut fp := flag.new_flag_parser([])
306 fp.application('flag_tool')
307 fp.version('v0.0.0')
308 fp.description('a description')
309 fp.bool('a_bool', 0, false, '')
310 fp.options.show.clear(.description)
311 assert !fp.usage().contains('Description:')
312}
313
314fn test_if_no_options_given_usage_message_does_not_contain_options() {
315 mut fp := flag.new_flag_parser([])
316 fp.application('flag_tool')
317 fp.version('v0.0.0')
318 assert !fp.usage().contains('Options:')
319}
320
321fn test_if_options_given_but_no_show_flag_header_usage_message_does_not_contain_flag_header() {
322 mut fp := flag.new_flag_parser([])
323 fp.application('flag_tool')
324 fp.version('v0.0.0')
325 fp.int('abc', `a`, 1, '')
326 fp.options.show.clear(.flags_header)
327 assert !fp.usage().contains('Options:')
328}
329
330fn test_if_options_given_but_no_show_usage_message_does_not_contain_options() {
331 mut fp := flag.new_flag_parser([])
332 fp.application('flag_tool')
333 fp.version('v0.0.0')
334 fp.int('abc', `a`, 1, '')
335 fp.options.show.clear(.flags)
336 assert !fp.usage().contains('Options:')
337}
338
339fn test_if_footer_given_but_no_show_usage_message_does_not_contain_footer() {
340 mut fp := flag.new_flag_parser([])
341 fp.application('flag_tool')
342 fp.version('v0.0.0')
343 fp.int('abc', `a`, 1, '')
344 fp.footers << 'footer1'
345 fp.options.show.clear(.footer)
346 assert !fp.usage().contains('footer1')
347}
348
349fn test_default_val_descriptions_for_bools() {
350 mut fp := flag.new_flag_parser([])
351 fp.bool('a_bool', `b`, true, '')
352
353 // by default, boolean flags contain no value description
354 assert !fp.usage().contains('<bool>')
355}
356
357fn test_custom_val_descriptions_for_bools() {
358 mut fp := flag.new_flag_parser([])
359 fp.bool('a_bool', `b`, true, '', val_desc: '<custom bool>')
360
361 // a custom boolean value description will be output
362 assert fp.usage().contains('<custom bool>')
363}
364
365fn test_default_val_descriptions_for_ints() {
366 mut fp := flag.new_flag_parser([])
367 fp.int_multi('a_int', `a`, '')
368 fp.int('b_int', `i`, 0, '')
369
370 assert fp.usage().contains('<multiple ints>')
371 assert fp.usage().contains('<int>')
372}
373
374fn test_custom_val_descriptions_for_ints() {
375 mut fp := flag.new_flag_parser([])
376 fp.int_multi('a_int', `a`, '', val_desc: '<multi custom int>')
377 fp.int('b_int', `i`, 0, '', val_desc: '<custom int>')
378
379 assert fp.usage().contains('<multi custom int>')
380 assert fp.usage().contains('<custom int>')
381}
382
383fn test_default_val_descriptions_for_floats() {
384 mut fp := flag.new_flag_parser([])
385 fp.float_multi('a_float', `a`, '')
386 fp.float('b_float', `f`, 0.0, '')
387
388 assert fp.usage().contains('<multiple floats>')
389 assert fp.usage().contains('<float>')
390}
391
392fn test_custom_val_descriptions_for_floats() {
393 mut fp := flag.new_flag_parser([])
394 fp.float_multi('a_float', `a`, '', val_desc: '<multi custom float>')
395 fp.float('b_float', `f`, 0.0, '', val_desc: '<custom float>')
396
397 assert fp.usage().contains('<multi custom float>')
398 assert fp.usage().contains('<custom float>')
399}
400
401fn test_default_val_descriptions_for_strings() {
402 mut fp := flag.new_flag_parser([])
403 fp.string_multi('a_string', `a`, '')
404 fp.string('b_string', `s`, '', '')
405
406 assert fp.usage().contains('<multiple strings>')
407 assert fp.usage().contains('<string>')
408}
409
410fn test_custom_val_descriptions_for_strings() {
411 mut fp := flag.new_flag_parser([])
412 fp.string_multi('a_string', `a`, '', val_desc: '<multi custom string>')
413 fp.string('b_string', `s`, '', '', val_desc: '<custom string>')
414
415 assert fp.usage().contains('<multi custom string>')
416 assert fp.usage().contains('<custom string>')
417}
418
419fn test_free_args_could_be_limited() {
420 mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
421 fp1.limit_free_args(1, 4)!
422 args := fp1.finalize() or {
423 assert false
424 return
425 }
426 assert args[0] == 'a'
427 assert args[1] == 'b'
428 assert args[2] == 'c'
429
430 mut fp2 := flag.new_flag_parser(['--', 'a'])
431 fp2.limit_free_args_to_at_least(1)!
432 args2 := fp2.finalize() or {
433 assert false
434 return
435 }
436 assert args2[0] == 'a'
437}
438
439fn test_error_for_to_few_free_args() {
440 mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
441 fp1.limit_free_args(5, 6)!
442 args := fp1.finalize() or {
443 assert err.msg().starts_with('Expected at least 5 arguments')
444 return
445 }
446 assert args.len < 0 // expect an error and need to use args
447}
448
449fn test_error_for_to_much_free_args() {
450 mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
451 fp1.limit_free_args(1, 2)!
452 args := fp1.finalize() or {
453 assert err.msg().starts_with('Expected at most 2 arguments')
454 return
455 }
456 assert args.len < 0 // expect an error and need to use args
457}
458
459fn test_could_expect_no_free_args() {
460 mut fp1 := flag.new_flag_parser(['a'])
461 fp1.limit_free_args(0, 0)!
462 args := fp1.finalize() or {
463 assert err.msg().starts_with('Expected no arguments')
464 return
465 }
466 assert args.len < 0 // expect an error and need to use args
467}
468
469fn test_allow_abbreviations() {
470 mut fp := flag.new_flag_parser(['-v', '-o', 'some_file', '-i', '42', '-f', '2.0'])
471 v := fp.bool('version', `v`, false, '')
472 o := fp.string('output', `o`, 'empty', '')
473 i := fp.int('count', `i`, 0, '')
474 f := fp.float('value', `f`, 0.0, '')
475 assert v == true
476 assert o == 'some_file'
477 assert i == 42
478 assert f == 2.0
479 u := fp.usage()
480 assert u.contains(' -v')
481 assert u.contains(' -o')
482 assert u.contains(' -i')
483 assert u.contains(' -f')
484 assert u.contains(' -o, --output <string>')
485 assert u.contains(' -i, --count <int>')
486 assert u.contains(' -f, --value <float>')
487}
488
489fn test_allow_kebab_options() {
490 default_value := 'this_is_the_default_value_of_long_option'
491 long_option_value := 'this_is_a_long_option_value_as_argument'
492 mut fp :=
493 flag.new_flag_parser(['--my-long-flag', 'true', '--my-long-option', long_option_value])
494 my_flag := fp.bool('my-long-flag', 0, false, 'flag with long-kebab-name')
495 my_option := fp.string('my-long-option', 0, default_value, 'string with long-kebab-name')
496 assert my_flag == true
497 assert my_option == long_option_value
498 u := fp.usage()
499 assert u.contains(' --my-long-flag')
500 assert u.contains(' --my-long-option')
501}
502
503fn test_not_provided_option_is_not_returned() {
504 mut fp := flag.new_flag_parser([])
505 fp.bool_opt('some-flag', `a`, '') or {
506 fp.int_opt('some-flag', `a`, '') or {
507 fp.float_opt('some-flag', `a`, '') or {
508 fp.string_opt('some-flag', `a`, '') or {
509 // Everything should not return
510 return
511 }
512 return
513 }
514 return
515 }
516 return
517 }
518 // If we reach here, one of them returned a value.
519 assert false
520}
521
522fn test_provided_option_is_returned() {
523 mut fp := flag.new_flag_parser(['-a', '-b', '3', '-c', 'hello', '-d', '3.14'])
524 a := fp.bool_opt('some-flag', `a`, '') or { panic('bool_opt did not return a bool') }
525 b := fp.int_opt('some-flag', `b`, '') or { panic('int_opt did not return an int') }
526 c := fp.string_opt('some-flag', `c`, '') or { panic('string_opt did not return a string') }
527 d := fp.float_opt('some-flag', `d`, '') or { panic('float_opt did not return a float') }
528 assert true == a
529 assert b == 3
530 assert c == 'hello'
531 assert d == 3.14
532}
533
534fn test_multiple_arguments() {
535 mut fp := flag.new_flag_parser([
536 '-a',
537 '2',
538 '-a',
539 '3',
540 '-a',
541 '5',
542 '-b',
543 'a',
544 '-b',
545 'c',
546 '-b',
547 'b',
548 '-c',
549 '1.23',
550 '-c',
551 '2.34',
552 '-c',
553 '3.45',
554 ])
555 // TODO: Move to array comparison once it's implemented
556 // assert fp.int_multi('some-flag', `a`, '') == [2, 3, 5] &&
557 // fp.string_multi('some-flag', `b`, '') == ['a', 'c', 'b'] &&
558 // fp.float_multi('some-flag', `c`, '') == [1.23, 2.34, 3.45]
559 a := fp.int_multi('some-flag', `a`, '')
560 b := fp.string_multi('some-flag', `b`, '')
561 c := fp.float_multi('some-flag', `c`, '')
562 assert a.len == 3
563 assert b.len == 3
564 assert c.len == 3
565 assert a[0] == 2
566 assert a[1] == 3
567 assert a[2] == 5
568 assert b[0] == 'a'
569 assert b[1] == 'c'
570 assert b[2] == 'b'
571 assert c[0] == 1.23
572 assert c[1] == 2.34
573 assert c[2] == 3.45
574}
575
576fn test_long_options_that_start_with_the_same_letter_as_another_short_option() {
577 mut fp := flag.new_flag_parser([
578 '--vabc',
579 '/abc',
580 ])
581 verbose := fp.bool('verbose', `v`, false, 'Be more verbose.')
582 vabc := fp.string('vabc', `x`, 'default',
583 'Another option that *may* conflict with v, but *should not*')
584 assert verbose == false
585 assert vabc == '/abc'
586}
587
588fn test_long_options_that_start_with_the_same_letter_as_another_short_option_both_set() {
589 mut fp := flag.new_flag_parser([
590 '-v',
591 '--vabc',
592 '/abc',
593 ])
594 verbose := fp.bool('verbose', `v`, false, 'Be more verbose.')
595 vabc := fp.string('vabc', `x`, 'default',
596 'Another option that *may* conflict with v, but *should not*')
597 assert verbose == true
598 assert vabc == '/abc'
599}
600
601fn test_single_dash() {
602 mut fp := flag.new_flag_parser([
603 '-',
604 ])
605 flag_update := fp.bool('update', `u`, false, 'Update tools')
606 assert flag_update == false
607}
608
609fn test_optional_flags() {
610 mut fp := flag.new_flag_parser(['-a', '10', '-b'])
611 fp.int_opt('some-flag', `a`, '') or {
612 assert false
613 return
614 }
615 b := fp.string_opt('another-flag', `b`, '') or { 'some_default_value' }
616 assert b == 'some_default_value'
617}
618
619fn test_dashdash_acts_as_parser_full_stop() {
620 mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello',
621 'some', 'other', 'parameters'])
622 a := fp.bool_opt('a-bool-flag', `a`, '') or { false }
623 b := fp.int_opt('an-int-flag', `b`, '') or { -1 }
624 c := fp.string_opt('a-string-flag', `c`, '') or { 'default' }
625 assert a == false
626 assert b == 5
627 assert c == 'default'
628 args := fp.finalize()!
629 assert args.len > 0
630 assert args[0] != '--'
631 assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters']
632}
633
634fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() {
635 mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--'])
636 b := fp.int_multi('an-int-flag', `b`, '')
637 assert b == [5, 4]
638 args := fp.finalize()!
639 assert args.len > 0
640}
641
642fn test_empty_string_with_flag() {
643 mut fp := flag.new_flag_parser([''])
644 s := fp.string('something', `s`, 'default', 'Hey parse me')
645}
646
647fn test_finalize_with_multi_shortargs() {
648 mut fp := flag.new_flag_parser(['-ab', '-c'])
649 a_bool := fp.bool('a_bool', `a`, false, '')
650 assert a_bool
651 b_bool := fp.bool('b_bool', `b`, false, '')
652 assert b_bool
653 c_bool := fp.bool('c_bool', `c`, false, '')
654 assert c_bool
655 additional_args := fp.finalize()!
656 println(additional_args.join_lines())
657 assert additional_args == []
658}
659
660fn test_finalize_with_multi_shortargs_different_order() {
661 mut fp := flag.new_flag_parser(['-ba', '-c'])
662 a_bool := fp.bool('a_bool', `a`, false, '')
663 assert a_bool
664 b_bool := fp.bool('b_bool', `b`, false, '')
665 assert b_bool
666 c_bool := fp.bool('c_bool', `c`, false, '')
667 assert c_bool
668 additional_args := fp.finalize()!
669 println(additional_args.join_lines())
670 assert additional_args == []
671}
672