mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
dadf147382
It's very often that someone will need to process values that were not provided separately (eg. generating a complex default value like in V). This commit allows the user to call the *_opt() functions instead of forcing them to provide some magical default values. * flag: Implement int_multi(), float_multi() and string_multi() These 3 functions are useful when the application expects a flag to be repeated more than once. A sample would be: v -cflags someflag -cflags secondflag This feature exposes the raw array that the flag parser internally keeps and allow the application to parse it however they want instead of dropping everything except the first element. * flag: Add documentation Add comments describing what *_opt() and *_multi() do.
320 lines
8.7 KiB
V
320 lines
8.7 KiB
V
import flag
|
|
|
|
fn test_if_flag_not_given_return_default_values() {
|
|
mut fp := flag.new_flag_parser([])
|
|
|
|
assert false == fp.bool('a_bool', false, '')
|
|
&& 42 == fp.int('an_int', 42, '')
|
|
&& 1.0 == fp.float('a_float', 1.0, '')
|
|
&& 'stuff' == fp.string('a_string', 'stuff', '')
|
|
}
|
|
|
|
|
|
fn test_could_define_application_name_and_version() {
|
|
mut fp := flag.new_flag_parser([])
|
|
fp.application('test app')
|
|
fp.version('0.0.42')
|
|
fp.description('some text')
|
|
|
|
assert fp.application_name == 'test app'
|
|
&& fp.application_version == '0.0.42'
|
|
&& fp.application_description == 'some text'
|
|
}
|
|
|
|
fn test_bool_flags_do_not_need_an_value() {
|
|
mut fp := flag.new_flag_parser(['--a_bool'])
|
|
|
|
assert true == fp.bool('a_bool', false, '')
|
|
}
|
|
|
|
fn test_flags_could_be_defined_with_eq() {
|
|
mut fp := flag.new_flag_parser([
|
|
'--an_int=42',
|
|
'--a_float=2.0',
|
|
'--bool_without',
|
|
'--a_string=stuff',
|
|
'--a_bool=true'])
|
|
|
|
assert 42 == fp.int('an_int', 666, '')
|
|
&& true == fp.bool('a_bool', false, '')
|
|
&& true == fp.bool('bool_without', false, '')
|
|
&& 2.0 == fp.float('a_float', 1.0, '')
|
|
&& 'stuff' == fp.string('a_string', 'not_stuff', '')
|
|
}
|
|
|
|
fn test_values_could_be_defined_without_eq() {
|
|
mut fp := flag.new_flag_parser([
|
|
'--an_int', '42',
|
|
'--a_float', '2.0',
|
|
'--bool_without',
|
|
'--a_string', 'stuff',
|
|
'--a_bool', 'true'])
|
|
|
|
assert 42 == fp.int('an_int', 666, '')
|
|
&& true == fp.bool('a_bool', false, '')
|
|
&& true == fp.bool('bool_without', false, '')
|
|
&& 2.0 == fp.float('a_float', 1.0, '')
|
|
&& 'stuff' == fp.string('a_string', 'not_stuff', '')
|
|
}
|
|
|
|
fn test_values_could_be_defined_mixed() {
|
|
mut fp := flag.new_flag_parser([
|
|
'--an_int', '42',
|
|
'--a_float=2.0',
|
|
'--bool_without',
|
|
'--a_string', 'stuff',
|
|
'--a_bool=true'])
|
|
|
|
assert 42 == fp.int('an_int', 666, '')
|
|
&& true == fp.bool('a_bool', false, '')
|
|
&& true == fp.bool('bool_without', false, '')
|
|
&& 2.0 == fp.float('a_float', 1.0, '')
|
|
&& 'stuff' == fp.string('a_string', 'not_stuff', '')
|
|
}
|
|
|
|
fn test_beaware_for_argument_names_with_same_prefix() {
|
|
mut fp := flag.new_flag_parser([
|
|
'--short', '5',
|
|
'--shorter=7'
|
|
])
|
|
|
|
assert 5 == fp.int('short', 666, '')
|
|
&& 7 == fp.int('shorter', 666, '')
|
|
}
|
|
|
|
fn test_beaware_for_argument_names_with_same_prefix_inverse() {
|
|
mut fp := flag.new_flag_parser([
|
|
'--shorter=7',
|
|
'--short', '5',
|
|
])
|
|
|
|
assert 5 == fp.int('short', 666, '')
|
|
&& 7 == fp.int('shorter', 666, '')
|
|
}
|
|
|
|
fn test_allow_to_skip_executable_path() {
|
|
mut fp := flag.new_flag_parser(['./path/to/execuable'])
|
|
|
|
fp.skip_executable()
|
|
|
|
args := fp.finalize() or {
|
|
assert false
|
|
return
|
|
}
|
|
assert !args.contains('./path/to/execuable')
|
|
}
|
|
|
|
fn test_none_flag_arguments_are_allowed() {
|
|
mut fp := flag.new_flag_parser([
|
|
'file1', '--an_int=2', 'file2', 'file3', '--bool_without', 'file4', '--outfile', 'outfile'])
|
|
|
|
assert 2 == fp.int('an_int', 666, '')
|
|
&& 'outfile' == fp.string('outfile', 'bad', '')
|
|
&& true == fp.bool('bool_without', false, '')
|
|
}
|
|
|
|
fn test_finalize_returns_none_flag_arguments_ordered() {
|
|
mut fp := flag.new_flag_parser(['d', 'b', 'x', 'a', '--outfile', 'outfile'])
|
|
fp.string('outfile', 'bad', '')
|
|
|
|
finalized := fp.finalize() or {
|
|
assert false
|
|
return
|
|
}
|
|
|
|
expected := ['d', 'b', 'x', 'a']
|
|
mut all_as_expected := true
|
|
for i, v in finalized {
|
|
all_as_expected = all_as_expected && v == expected[i]
|
|
}
|
|
assert all_as_expected
|
|
}
|
|
|
|
fn test_finalize_returns_error_for_unknown_flags() {
|
|
mut fp := flag.new_flag_parser(['--known', '--unknown'])
|
|
|
|
fp.bool('known', false, '')
|
|
|
|
finalized := fp.finalize() or {
|
|
assert err == 'Unknown argument \'unknown\''
|
|
return
|
|
}
|
|
assert finalized.len < 0 // expect error to be returned
|
|
}
|
|
|
|
fn test_allow_to_build_usage_message() {
|
|
mut fp := flag.new_flag_parser([])
|
|
fp.limit_free_args(1, 4)
|
|
fp.application('flag_tool')
|
|
fp.version('v0.0.0')
|
|
fp.description('some short information about this tool')
|
|
|
|
fp.int('an_int', 666, 'some int to define')
|
|
fp.bool('a_bool', false, 'some bool to define')
|
|
fp.bool('bool_without_but_really_big', false, 'this should appear on the next line')
|
|
fp.float('a_float', 1.0, 'some float as well')
|
|
fp.string('a_string', 'not_stuff', 'your credit card number')
|
|
|
|
usage := fp.usage()
|
|
mut all_strings_found := true
|
|
for s in ['flag_tool', 'v0.0.0',
|
|
'an_int <int>', 'a_bool', 'bool_without', 'a_float <float>', 'a_string <string>',
|
|
'some int to define',
|
|
'some bool to define',
|
|
'this should appear on the next line',
|
|
'some float as well',
|
|
'your credit card number',
|
|
'The arguments should be at least 1 and at most 4 in number.',
|
|
'Usage', 'Options:', 'Description:',
|
|
'some short information about this tool'] {
|
|
if !usage.contains(s) {
|
|
eprintln(' missing \'$s\' in usage message')
|
|
all_strings_found = false
|
|
}
|
|
}
|
|
assert all_strings_found
|
|
}
|
|
|
|
fn test_if_no_description_given_usage_message_does_not_contain_descpription() {
|
|
mut fp := flag.new_flag_parser([])
|
|
fp.application('flag_tool')
|
|
fp.version('v0.0.0')
|
|
|
|
fp.bool('a_bool', false, '')
|
|
|
|
assert !fp.usage().contains('Description:')
|
|
}
|
|
|
|
fn test_if_no_options_given_usage_message_does_not_contain_options() {
|
|
mut fp := flag.new_flag_parser([])
|
|
fp.application('flag_tool')
|
|
fp.version('v0.0.0')
|
|
|
|
assert !fp.usage().contains('Options:')
|
|
}
|
|
|
|
fn test_free_args_could_be_limited() {
|
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
|
fp1.limit_free_args(1, 4)
|
|
args := fp1.finalize() or {
|
|
assert false
|
|
return
|
|
}
|
|
assert args[0] == 'a' && args[1] == 'b' && args[2] == 'c'
|
|
}
|
|
|
|
fn test_error_for_to_few_free_args() {
|
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
|
fp1.limit_free_args(5, 6)
|
|
args := fp1.finalize() or {
|
|
assert err.starts_with('Expected at least 5 arguments')
|
|
return
|
|
}
|
|
assert args.len < 0 // expect an error and need to use args
|
|
}
|
|
|
|
fn test_error_for_to_much_free_args() {
|
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
|
fp1.limit_free_args(1, 2)
|
|
args := fp1.finalize() or {
|
|
assert err.starts_with('Expected at most 2 arguments')
|
|
return
|
|
}
|
|
assert args.len < 0 // expect an error and need to use args
|
|
}
|
|
|
|
fn test_could_expect_no_free_args() {
|
|
mut fp1 := flag.new_flag_parser(['a'])
|
|
fp1.limit_free_args(0, 0)
|
|
args := fp1.finalize() or {
|
|
assert err.starts_with('Expected no arguments')
|
|
return
|
|
}
|
|
assert args.len < 0 // expect an error and need to use args
|
|
}
|
|
|
|
fn test_allow_abreviations() {
|
|
mut fp := flag.new_flag_parser(['-v', '-o', 'some_file', '-i', '42', '-f', '2.0'])
|
|
|
|
v := fp.bool_('version', `v`, false, '')
|
|
o := fp.string_('output', `o`, 'empty', '')
|
|
i := fp.int_('count', `i`, 0, '')
|
|
f := fp.float_('value', `f`, 0.0, '')
|
|
|
|
assert v && o == 'some_file' && i == 42 && f == 2.0
|
|
|
|
u := fp.usage()
|
|
assert u.contains(' -v') && u.contains(' -o') && u.contains(' -i') && u.contains(' -f')
|
|
}
|
|
|
|
fn test_allow_kebab_options() {
|
|
default_value := 'this_is_the_default_value_of_long_option'
|
|
long_option_value := 'this_is_a_long_option_value_as_argument'
|
|
|
|
mut fp := flag.new_flag_parser(['--my-long-flag', 'true', '--my-long-option', long_option_value ])
|
|
|
|
my_flag := fp.bool('my-long-flag', false, 'flag with long-kebab-name')
|
|
my_option := fp.string('my-long-option', default_value, 'string with long-kebab-name')
|
|
|
|
assert my_flag == true
|
|
assert my_option == long_option_value
|
|
|
|
u := fp.usage()
|
|
assert u.contains(' --my-long-flag')
|
|
assert u.contains(' --my-long-option')
|
|
}
|
|
|
|
fn test_not_provided_option_is_not_returned() {
|
|
mut fp := flag.new_flag_parser([])
|
|
fp.bool_opt('some-flag', `a`, '') or {
|
|
fp.int_opt('some-flag', `a`, '') or {
|
|
fp.float_opt('some-flag', `a`, '') or {
|
|
fp.string_opt('some-flag', `a`, '') or {
|
|
//Everything should not return
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//If we reach here, one of them returned a value.
|
|
assert false
|
|
}
|
|
|
|
fn test_provided_option_is_returned() {
|
|
mut fp := flag.new_flag_parser(['-a', '-b', '3', '-c', 'hello', '-d', '3.14'])
|
|
a := fp.bool_opt('some-flag', `a`, '') or {
|
|
panic('bool_opt did not return a bool')
|
|
}
|
|
b := fp.int_opt('some-flag', `b`, '') or {
|
|
panic('int_opt did not return an int')
|
|
}
|
|
c := fp.string_opt('some-flag', `c`, '') or {
|
|
panic('string_opt did not return a string')
|
|
}
|
|
d := fp.float_opt('some-flag', `d`, '') or {
|
|
panic('float_opt did not return a float')
|
|
}
|
|
assert a && b == 3 && c == 'hello' && d == 3.14
|
|
}
|
|
|
|
fn test_multiple_arguments() {
|
|
mut fp := flag.new_flag_parser([
|
|
'-a', '2', '-a', '3', '-a', '5',
|
|
'-b', 'a', '-b', 'c', '-b', 'b',
|
|
'-c', '1.23', '-c', '2.34', '-c', '3.45'
|
|
])
|
|
|
|
//TODO Move to array comparison once it's implemented
|
|
//assert fp.int_multi('some-flag', `a`, '') == [2, 3, 5] &&
|
|
// fp.string_multi('some-flag', `b`, '') == ['a', 'c', 'b'] &&
|
|
// fp.float_multi('some-flag', `c`, '') == [1.23, 2.34, 3.45]
|
|
|
|
a := fp.int_multi('some-flag', `a`, '')
|
|
b := fp.string_multi('some-flag', `b`, '')
|
|
c := fp.float_multi('some-flag', `c`, '')
|
|
assert a.len == 3 && b.len == 3 && c.len == 3
|
|
assert a[0] == 2 && a[1] == 3 && a[2] == 5
|
|
assert b[0] == 'a' && b[1] == 'c' && b[2] == 'b'
|
|
assert c[0] == 1.23 && c[1] == 2.34 && c[2] == 3.45
|
|
}
|