v / vlib / flag / flag_to_misc_test.v
204 lines · 182 sloc · 6.82 KB · d27ab09cdfa702c8d548d4ccccf0361d1bb76380
Raw
1import flag
2
3const all_style_enums = [flag.Style.short, .short_long, .long, .v, .v_flag_parser]
4const posix_gnu_style_enums = [flag.Style.short, .short_long, .long]
5const mixed_args = ['/path/to/exe', '-vv', 'vvv', '-version', '--mix', '--mix-all=all', '-ldflags',
6 '-m', '2', '-fgh', '["test", "test"]', '-m', '{map: 2, ml-q:"hello"}']
7
8const posix_and_gnu_args = ['-vv', 'vvv', '-mwindows', '-d', 'one', '--device=two', '--amount=8',
9 '-d', 'three']
10
11const posix_and_gnu_args_with_subcmd = ['/path/to/exe', 'subcmd', '-vv', 'vvv', '-mwindows', '-d',
12 'one', '--device=two', '--amount=8', '-d', 'three']
13
14const posix_and_gnu_args_with_paths = ['/path/to/exe', '-vv', 'vvv', '-mwindows', '-d', 'one',
15 '--device=two', '--amount=8', '-d', 'three', '/path/to/a', '/path/to/b']
16
17const posix_args_error = ['/path/to/exe', '-vv', 'vvv', '-mwindows', '-m', 'gnu']
18const gnu_args = ['--f=10.2', '--mix', '--test=test', '--amount=5', '--version', 'other']
19const gnu_args_error = ['--f=10.2', '--mix', '--test=test', '--amount=5', '--version', 'other',
20 'oo']
21const ignore_args_error = ['--show-version', '--some-test=ouch', '--amount=5', 'end']
22
23struct Config {
24 mix bool
25 linker_option string @[only: m]
26 mix_hard bool @[json: muh] // Test that no other attributes get picked up
27 def_test string = 'def' @[long: test; short: t]
28 device []string @[short: d]
29 paths []string @[tail]
30 amount int = 1
31 verbosity int @[repeats; short: v]
32 show_version bool @[long: version]
33 no_long_beef bool @[only: n]
34}
35
36struct LongConfig {
37 f f32
38 mix bool
39 some_test string = 'abc' @[long: test]
40 path string @[tail]
41 amount int = 1
42 show_version bool @[long: version]
43}
44
45struct IgnoreConfig {
46 some_test string = 'abc' @[ignore]
47 path string @[tail]
48 amount int = 1
49 show_version bool
50}
51
52fn test_flags() {
53 // Test .short_long parse style
54 config1, _ := flag.to_struct[Config](posix_and_gnu_args_with_subcmd, skip: 1)!
55 assert config1.mix == false
56 assert config1.verbosity == 5
57 assert config1.amount == 8
58 assert config1.def_test == 'def'
59 assert 'one' in config1.device
60 assert 'two' in config1.device
61 assert 'three' in config1.device
62 assert config1.linker_option == 'windows'
63
64 config2, _ := flag.to_struct[Config](posix_and_gnu_args)!
65 assert config2.mix == false
66 assert config2.verbosity == 5
67 assert config2.amount == 8
68 assert config2.def_test == 'def'
69 assert 'one' in config2.device
70 assert 'two' in config2.device
71 assert 'three' in config2.device
72 assert config2.device.len == 3
73 assert config2.linker_option == 'windows'
74
75 mut posix_and_gnu_args_plus_test := posix_and_gnu_args.clone()
76 posix_and_gnu_args_plus_test << ['--test=ok', '-d', 'four']
77 config3, _ := flag.to_struct[Config](posix_and_gnu_args_plus_test)!
78 assert config3.mix == false
79 assert config3.verbosity == 5
80 assert config3.amount == 8
81 assert config3.def_test == 'ok'
82 assert config3.device.len == 4
83 assert 'one' == config3.device[0]
84 assert 'two' == config3.device[1]
85 assert 'three' == config3.device[2]
86 assert 'four' == config3.device[3]
87 assert config3.linker_option == 'windows'
88
89 config4, _ := flag.to_struct[Config](posix_and_gnu_args_with_paths, skip: 1)!
90 assert config4.verbosity == 5
91 assert config4.amount == 8
92 assert config4.def_test == 'def'
93 assert config4.device.len == 3
94 assert 'one' == config4.device[0]
95 assert 'two' == config4.device[1]
96 assert 'three' == config4.device[2]
97 assert config4.linker_option == 'windows'
98 assert config4.paths.len == 2
99 assert config4.paths[0] == '/path/to/a'
100 assert config4.paths[1] == '/path/to/b'
101}
102
103fn test_long_flags() {
104 // Test .long parse style
105 lc1, _ := flag.to_struct[LongConfig](gnu_args, style: .long)!
106 assert lc1.f == 10.2
107 assert lc1.mix == true
108 assert lc1.some_test == 'test'
109 assert lc1.path == 'other'
110 assert lc1.amount == 5
111 assert lc1.show_version == true
112}
113
114fn test_flag_error_messages() {
115 // Test error for GNU long flag in .short (Posix) mode
116 if _, _ := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
117 skip: 1
118 style: .short
119 )
120 {
121 assert false, 'flags should not have reached this assert'
122 } else {
123 assert err.msg() == 'long delimiter `--` encountered in flag `--device=two` in short (POSIX) style parsing mode'
124 }
125
126 // Test double mapping of flags
127 if _, _ := flag.to_struct[Config](posix_args_error, skip: 1) {
128 assert false, 'flags should not have reached this assert'
129 } else {
130 assert err.msg() == 'flag `-m gnu` is already mapped to field `linker_option` via `-m windows`'
131 }
132
133 for e_num in all_style_enums {
134 // Test no match for non-flag as first arg (usually the `/path/to/executable`) - which must be skipped with `.skip`
135 if _, no_matches := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
136 style: e_num
137 )
138 {
139 assert no_matches == ['/path/to/exe', 'subcmd'] // index 0 = executable, index 1 = subcmd
140 }
141 }
142
143 for e_num in posix_gnu_style_enums {
144 if _, _ := flag.to_struct[Config](mixed_args, skip: 1, style: e_num) {
145 assert false, 'flags should not have reached this assert'
146 } else {
147 if e_num == .short {
148 assert err.msg() == 'long delimiter `--` encountered in flag `--mix` in short (POSIX) style parsing mode'
149 } else if e_num == .long {
150 assert err.msg() == 'short delimiter `-` encountered in flag `-vv` in long (GNU) style parsing mode'
151 } else {
152 assert err.msg() == 'flag `-m {map: 2, ml-q:"hello"}` is already mapped to field `linker_option` via `-m 2`'
153 }
154 assert true
155 }
156 }
157 if _, no_matches := flag.to_struct[LongConfig](gnu_args_error, style: .long) {
158 assert no_matches == ['oo']
159 } else {
160 assert false, 'flags should not have reached this assert'
161 }
162
163 if _, _ := flag.to_struct[LongConfig](['--version=1.2.3'], style: .long) {
164 assert false, 'flags should not have reached this assert'
165 } else {
166 assert err.msg() == 'flag `--version=1.2.3` can not be assigned to bool field "show_version"'
167 }
168 if _, no_matches := flag.to_struct[IgnoreConfig](ignore_args_error, style: .long) {
169 assert no_matches == ['--some-test=ouch']
170 }
171}
172
173fn test_flag_no_error_messages_when_relaxed() {
174 // Test that there's no errors in `mode: .relaxed`
175 _, no_matches1 := flag.to_struct[Config](posix_and_gnu_args_with_subcmd,
176 skip: 1
177 style: .short
178 mode: .relaxed
179 )!
180 assert no_matches1 == ['subcmd', '--device=two', '--amount=8']
181
182 _, no_matches2 := flag.to_struct[LongConfig](gnu_args_error,
183 style: .long
184 mode: .relaxed
185 )!
186 assert no_matches2 == ['oo']
187
188 if _, _ := flag.to_struct[LongConfig](['--version=1.2.3'],
189 style: .long
190 mode: .relaxed
191 )
192 {
193 assert false, 'flags should not have reached this assert'
194 } else {
195 // Type errors should not be ignored, only non-matching flags/args
196 assert err.msg() == 'flag `--version=1.2.3` can not be assigned to bool field "show_version"'
197 }
198
199 _, no_matches3 := flag.to_struct[IgnoreConfig](ignore_args_error,
200 style: .long
201 mode: .relaxed
202 )!
203 assert no_matches3 == ['--some-test=ouch']
204}
205