import flag fn test_if_flag_not_given_return_default_values() { mut fp := flag.new_flag_parser([]) assert false == fp.bool('a_bool', 0, false, '') && 42 == fp.int('an_int', 0, 42, '') && 1.0 == fp.float('a_float', 0, 1.0, '') && 'stuff' == fp.string('a_string', 0, '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', 0, 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', 0, 666, '') && true == fp.bool('a_bool', 0, false, '') && true == fp.bool('bool_without', 0, false, '') && 2.0 == fp.float('a_float', 0, 1.0, '') && 'stuff' == fp.string('a_string', 0, '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', 0, 666, '') && true == fp.bool('a_bool', 0, false, '') && true == fp.bool('bool_without', 0, false, '') && 2.0 == fp.float('a_float', 0, 1.0, '') && 'stuff' == fp.string('a_string', 0, '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', 0, 666, '') && true == fp.bool('a_bool', 0, false, '') && true == fp.bool('bool_without', 0, false, '') && 2.0 == fp.float('a_float', 0, 1.0, '') && 'stuff' == fp.string('a_string', 0, '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', 0, 666, '') && 7 == fp.int('shorter', 0, 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', 0, 666, '') && 7 == fp.int('shorter', 0, 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', 0, 666, '') && 'outfile' == fp.string('outfile', 0, 'bad', '') && true == fp.bool('bool_without', 0, false, '') } fn test_finalize_returns_none_flag_arguments_ordered() { mut fp := flag.new_flag_parser(['d', 'b', 'x', 'a', '--outfile', 'outfile']) fp.string('outfile', 0, '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', 0, 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', 0, 666, 'some int to define') fp.bool('a_bool', 0, false, 'some bool to define') fp.bool('bool_without_but_really_big', 0, false, 'this should appear on the next line') fp.float('a_float', 0, 1.0, 'some float as well') fp.string('a_string', 0, 'not_stuff', 'your credit card number') usage := fp.usage() mut all_strings_found := true for s in ['flag_tool', 'v0.0.0', 'an_int ', 'a_bool', 'bool_without', 'a_float ', 'a_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', 0, 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') assert u.contains(' -o, --output ') assert u.contains(' -i, --count ') assert u.contains(' -f, --value ') } 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', 0, false, 'flag with long-kebab-name') my_option := fp.string('my-long-option', 0, 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 } fn test_long_options_that_start_with_the_same_letter_as_another_short_option() { mut fp := flag.new_flag_parser([ '--vabc', '/abc', ]) verbose := fp.bool('verbose', `v`, false, 'Be more verbose.') vabc := fp.string('vabc', `x`, 'default', 'Another option that *may* conflict with v, but *should not*') assert verbose == false assert vabc == '/abc' } fn test_long_options_that_start_with_the_same_letter_as_another_short_option_both_set() { mut fp := flag.new_flag_parser([ '-v', '--vabc', '/abc', ]) verbose := fp.bool('verbose', `v`, false, 'Be more verbose.') vabc := fp.string('vabc', `x`, 'default', 'Another option that *may* conflict with v, but *should not*') assert verbose == true assert vabc == '/abc' }