mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
205 lines
6.8 KiB
V
205 lines
6.8 KiB
V
import flag
|
|
|
|
const all_style_enums = [flag.Style.short, .short_long, .long, .v, .v_flag_parser]
|
|
const posix_gnu_style_enums = [flag.Style.short, .short_long, .long]
|
|
const mixed_args = ['/path/to/exe', '-vv', 'vvv', '-version', '--mix', '--mix-all=all', '-ldflags',
|
|
'-m', '2', '-fgh', '["test", "test"]', '-m', '{map: 2, ml-q:"hello"}']
|
|
|
|
const posix_and_gnu_args = ['-vv', 'vvv', '-mwindows', '-d', 'one', '--device=two', '--amount=8',
|
|
'-d', 'three']
|
|
|
|
const posix_and_gnu_args_with_subcmd = ['/path/to/exe', 'subcmd', '-vv', 'vvv', '-mwindows', '-d',
|
|
'one', '--device=two', '--amount=8', '-d', 'three']
|
|
|
|
const posix_and_gnu_args_with_paths = ['/path/to/exe', '-vv', 'vvv', '-mwindows', '-d', 'one',
|
|
'--device=two', '--amount=8', '-d', 'three', '/path/to/a', '/path/to/b']
|
|
|
|
const posix_args_error = ['/path/to/exe', '-vv', 'vvv', '-mwindows', '-m', 'gnu']
|
|
const gnu_args = ['--f=10.2', '--mix', '--test=test', '--amount=5', '--version', 'other']
|
|
const gnu_args_error = ['--f=10.2', '--mix', '--test=test', '--amount=5', '--version', 'other',
|
|
'oo']
|
|
const ignore_args_error = ['--show-version', '--some-test=ouch', '--amount=5', 'end']
|
|
|
|
struct Config {
|
|
mix bool
|
|
linker_option string @[only: m]
|
|
mix_hard bool @[json: muh] // Test that no other attributes get picked up
|
|
def_test string = 'def' @[long: test; short: t]
|
|
device []string @[short: d]
|
|
paths []string @[tail]
|
|
amount int = 1
|
|
verbosity int @[repeats; short: v]
|
|
show_version bool @[long: version]
|
|
no_long_beef bool @[only: n]
|
|
}
|
|
|
|
struct LongConfig {
|
|
f f32
|
|
mix bool
|
|
some_test string = 'abc' @[long: test]
|
|
path string @[tail]
|
|
amount int = 1
|
|
show_version bool @[long: version]
|
|
}
|
|
|
|
struct IgnoreConfig {
|
|
some_test string = 'abc' @[ignore]
|
|
path string @[tail]
|
|
amount int = 1
|
|
show_version bool
|
|
}
|
|
|
|
fn test_flags() {
|
|
// Test .short_long parse style
|
|
config1, _ := flag.to_struct[Config](posix_and_gnu_args_with_subcmd, skip: 1)!
|
|
assert config1.mix == false
|
|
assert config1.verbosity == 5
|
|
assert config1.amount == 8
|
|
assert config1.def_test == 'def'
|
|
assert 'one' in config1.device
|
|
assert 'two' in config1.device
|
|
assert 'three' in config1.device
|
|
assert config1.linker_option == 'windows'
|
|
|
|
config2, _ := flag.to_struct[Config](posix_and_gnu_args)!
|
|
assert config2.mix == false
|
|
assert config2.verbosity == 5
|
|
assert config2.amount == 8
|
|
assert config2.def_test == 'def'
|
|
assert 'one' in config2.device
|
|
assert 'two' in config2.device
|
|
assert 'three' in config2.device
|
|
assert config2.device.len == 3
|
|
assert config2.linker_option == 'windows'
|
|
|
|
mut posix_and_gnu_args_plus_test := posix_and_gnu_args.clone()
|
|
posix_and_gnu_args_plus_test << ['--test=ok', '-d', 'four']
|
|
config3, _ := flag.to_struct[Config](posix_and_gnu_args_plus_test)!
|
|
assert config3.mix == false
|
|
assert config3.verbosity == 5
|
|
assert config3.amount == 8
|
|
assert config3.def_test == 'ok'
|
|
assert config3.device.len == 4
|
|
assert 'one' == config3.device[0]
|
|
assert 'two' == config3.device[1]
|
|
assert 'three' == config3.device[2]
|
|
assert 'four' == config3.device[3]
|
|
assert config3.linker_option == 'windows'
|
|
|
|
config4, _ := flag.to_struct[Config](posix_and_gnu_args_with_paths, skip: 1)!
|
|
assert config4.verbosity == 5
|
|
assert config4.amount == 8
|
|
assert config4.def_test == 'def'
|
|
assert config4.device.len == 3
|
|
assert 'one' == config4.device[0]
|
|
assert 'two' == config4.device[1]
|
|
assert 'three' == config4.device[2]
|
|
assert config4.linker_option == 'windows'
|
|
assert config4.paths.len == 2
|
|
assert config4.paths[0] == '/path/to/a'
|
|
assert config4.paths[1] == '/path/to/b'
|
|
}
|
|
|
|
fn test_long_flags() {
|
|
// Test .long parse style
|
|
lc1, _ := flag.to_struct[LongConfig](gnu_args, style: .long)!
|
|
assert lc1.f == 10.2
|
|
assert lc1.mix == true
|
|
assert lc1.some_test == 'test'
|
|
assert lc1.path == 'other'
|
|
assert lc1.amount == 5
|
|
assert lc1.show_version == true
|
|
}
|
|
|
|
fn test_flag_error_messages() {
|
|
// Test error for GNU long flag in .short (Posix) mode
|
|
if _, _ := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
|
|
skip: 1
|
|
style: .short
|
|
)
|
|
{
|
|
assert false, 'flags should not have reached this assert'
|
|
} else {
|
|
assert err.msg() == 'long delimiter `--` encountered in flag `--device=two` in short (POSIX) style parsing mode'
|
|
}
|
|
|
|
// Test double mapping of flags
|
|
if _, _ := flag.to_struct[Config](posix_args_error, skip: 1) {
|
|
assert false, 'flags should not have reached this assert'
|
|
} else {
|
|
assert err.msg() == 'flag `-m gnu` is already mapped to field `linker_option` via `-m windows`'
|
|
}
|
|
|
|
for e_num in all_style_enums {
|
|
// Test no match for non-flag as first arg (usually the `/path/to/executable`) - which must be skipped with `.skip`
|
|
if _, no_matches := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
|
|
style: e_num
|
|
)
|
|
{
|
|
assert no_matches == ['/path/to/exe', 'subcmd'] // index 0 = executable, index 1 = subcmd
|
|
}
|
|
}
|
|
|
|
for e_num in posix_gnu_style_enums {
|
|
if _, _ := flag.to_struct[Config](mixed_args, skip: 1, style: e_num) {
|
|
assert false, 'flags should not have reached this assert'
|
|
} else {
|
|
if e_num == .short {
|
|
assert err.msg() == 'long delimiter `--` encountered in flag `--mix` in short (POSIX) style parsing mode'
|
|
} else if e_num == .long {
|
|
assert err.msg() == 'short delimiter `-` encountered in flag `-vv` in long (GNU) style parsing mode'
|
|
} else {
|
|
assert err.msg() == 'flag `-m {map: 2, ml-q:"hello"}` is already mapped to field `linker_option` via `-m 2`'
|
|
}
|
|
assert true
|
|
}
|
|
}
|
|
if _, no_matches := flag.to_struct[LongConfig](gnu_args_error, style: .long) {
|
|
assert no_matches == ['oo']
|
|
} else {
|
|
assert false, 'flags should not have reached this assert'
|
|
}
|
|
|
|
if _, _ := flag.to_struct[LongConfig](['--version=1.2.3'], style: .long) {
|
|
assert false, 'flags should not have reached this assert'
|
|
} else {
|
|
assert err.msg() == 'flag `--version=1.2.3` can not be assigned to bool field "show_version"'
|
|
}
|
|
if _, no_matches := flag.to_struct[IgnoreConfig](ignore_args_error, style: .long) {
|
|
assert no_matches == ['--some-test=ouch']
|
|
}
|
|
}
|
|
|
|
fn test_flag_no_error_messages_when_relaxed() {
|
|
// Test that there's no errors in `mode: .relaxed`
|
|
_, no_matches1 := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
|
|
skip: 1
|
|
style: .short
|
|
mode: .relaxed
|
|
)!
|
|
assert no_matches1 == ['subcmd', '--device=two', '--amount=8']
|
|
|
|
_, no_matches2 := flag.to_struct[LongConfig](gnu_args_error,
|
|
style: .long
|
|
mode: .relaxed
|
|
)!
|
|
assert no_matches2 == ['oo']
|
|
|
|
if _, _ := flag.to_struct[LongConfig](['--version=1.2.3'],
|
|
style: .long
|
|
mode: .relaxed
|
|
)
|
|
{
|
|
assert false, 'flags should not have reached this assert'
|
|
} else {
|
|
// Type errors should not be ignored, only non-matching flags/args
|
|
assert err.msg() == 'flag `--version=1.2.3` can not be assigned to bool field "show_version"'
|
|
}
|
|
|
|
_, no_matches3 := flag.to_struct[IgnoreConfig](ignore_args_error,
|
|
style: .long
|
|
mode: .relaxed
|
|
)!
|
|
assert no_matches3 == ['--some-test=ouch']
|
|
}
|