OILS / stdlib / ysh / args-test.ysh View on Github | oilshell.org

305 lines, 161 significant
1#!bin/ysh
2
3# TODO: you should only have to pick parser
4# and you can use 'args parser' I guess
5
6use $LIB_YSH/args.ysh --pick parser flag arg rest parseArgs
7
8source $LIB_YSH/yblocks.ysh
9
10# TODO: why doesn't this work? Is there a buffering problem wtih read --all?
11# Why would it not show up with source though?
12#use $LIB_YSH/yblocks.ysh --pick yb-capture
13
14# Can't be 'use' because we're using shell functions?
15source $LIB_OSH/byo-server.sh
16
17proc test-basic {
18 parser (&spec) {
19 flag -v --verbose (help="Verbosely") # default is Bool, false
20
21 flag -P --max-procs ('int', default=-1, help='''
22 Run at most P processes at a time
23 ''')
24
25 flag -i --invert ('bool', default=true, help='''
26 Long multiline
27 Description
28 ''')
29
30 arg src (help='Source')
31 arg dest (help='Dest')
32
33 rest files
34 }
35
36 var args = parseArgs(spec, :| mysrc -P 12 mydest a b c |)
37
38 assert [false === args.verbose]
39
40 # TODO: clean up this JSON
41 var expected = {"src":"mysrc","max-procs":12,"dest":"mydest","files":["a","b","c"],"verbose":false,"invert":true}
42 assert [expected === args]
43}
44
45proc test-2 {
46 ### Bool flag, positional args, more positional
47
48 parser (&spec) {
49 flag -v --verbose ('bool')
50 arg src
51 arg dst
52
53 rest more # allow more args
54 }
55
56 var argv = ['-v', 'src/path', 'dst/path', 'x', 'y', 'z']
57
58 var args = parseArgs(spec, argv)
59
60 #pp test_ (args)
61
62 assert [true === args.verbose]
63 assert ['src/path' === args.src]
64 assert ['dst/path' === args.dst]
65 assert [ :| x y z | === args.more]
66}
67
68proc test-default-values {
69
70 parser (&spec) {
71 flag -S --sanitize ('bool', default=false)
72 flag -v --verbose ('bool', default=false)
73 flag -P --max-procs ('int') # Will set to null (the default default)
74 }
75
76 var args = parseArgs(spec, [])
77
78 #pp test_ (args)
79 var expected = {"sanitize":false,"verbose":false,"max-procs":null}
80 assert [expected === args]
81}
82
83proc test-multiple-argv-arrays {
84 parser (&spec) {
85 flag -v --verbose ('bool', default=false)
86 flag -c --count ('int', default=120)
87 arg file
88 }
89
90 # TODO: argCases should go above
91 var argsCases = [
92 :| -v --count 120 example.sh |,
93 :| -v --count 120 example.sh -v |, # duplicate flags are ignored
94 :| -v --count 120 example.sh -v --count 150 |, # the last duplicate has precedence
95 ]
96
97 yb-capture (&r) {
98 for args in (argsCases) {
99 var args_str = join(args, ' ')
100 echo "---------- $args_str ----------"
101 echo "\$ bin/ysh example.sh $args_str"
102 pp test_ (parseArgs(spec, args))
103
104 echo
105 }
106 }
107
108 #pp (r.stdout)
109
110 var expected = '''
111 ---------- -v --count 120 example.sh ----------
112 $ bin/ysh example.sh -v --count 120 example.sh
113 (Dict) {"verbose":true,"count":120,"file":"example.sh"}
114
115 ---------- -v --count 120 example.sh -v ----------
116 $ bin/ysh example.sh -v --count 120 example.sh -v
117 (Dict) {"verbose":true,"count":120,"file":"example.sh"}
118
119 ---------- -v --count 120 example.sh -v --count 150 ----------
120 $ bin/ysh example.sh -v --count 120 example.sh -v --count 150
121 (Dict) {"verbose":true,"count":150,"file":"example.sh"}
122
123 '''
124
125 assert [expected === r.stdout]
126}
127
128proc test-duplicate-names-are-errors {
129 try {
130 parser (&spec) {
131 flag -n --name
132 flag -N --name
133 }
134 }
135 assert [3 === _error.code]
136
137 try {
138 parser (&spec) {
139 flag -n --name
140 arg name
141 }
142 }
143 assert [3 === _error.code]
144
145 try {
146 parser (&spec) {
147 arg name
148 flag -o --other
149 arg name
150 }
151 }
152 assert [3 === _error.code]
153}
154
155proc test-more-errors {
156
157 parser (&spec) {
158 flag -v --verbose
159 flag -n --num ('int', required=true)
160
161 arg action
162 arg other (required=false)
163 }
164
165 try { call parseArgs(spec, :| -n 10 action other extra |) }
166 assert [2 === _error.code]
167
168 try { call parseArgs(spec, :| -n |) }
169 assert [2 === _error.code]
170
171 try { call parseArgs(spec, :| -n -v |) }
172 assert [2 === _error.code]
173
174 try { = parseArgs(spec, :| -n 10 |) }
175 assert [2 === _error.code]
176
177 try { call parseArgs(spec, :| -v action |) }
178 assert [2 === _error.code]
179
180 try { call parseArgs(spec, :| --unknown |) }
181 assert [2 === _error.code]
182}
183
184proc test-print-spec {
185
186 parser (&spec) {
187 flag -v --verbose ('bool')
188 arg src
189 arg dst
190
191 rest more # allow more args
192 }
193
194 yb-capture (&r) {
195 json write (spec)
196 }
197
198 var expected = '''
199 {
200 "flags": [
201 {
202 "short": "-v",
203 "long": "--verbose",
204 "name": "verbose",
205 "type": "bool",
206 "default": false,
207 "help": null
208 }
209 ],
210 "args": [
211 {
212 "name": "src",
213 "help": null
214 },
215 {
216 "name": "dst",
217 "help": null
218 }
219 ],
220 "rest": "more"
221 }
222 '''
223
224 assert [expected === r.stdout]
225}
226
227proc test-vs-python3-argparse {
228 var spec = {
229 flags: [
230 {short: '-v', long: '--verbose', name: 'verbose', type: null, default: '', help: 'Enable verbose logging'},
231 {short: '-c', long: '--count', name: 'count', type: 'int', default: 80, help: 'Maximum line length'},
232 ],
233 args: [
234 {name: 'file', type: 'str', help: 'File to check line lengths of'}
235 ],
236 rest: null,
237 }
238
239 var argsCases = [
240 :| -v --count 120 example.sh |,
241 :| -v --count 120 example.sh -v |, # duplicate flags are ignored
242 :| -v --count 120 example.sh -v --count 150 |, # the last duplicate has precedence
243 ]
244
245 var argparse_py = '''
246 import argparse
247 import sys
248
249 spec = argparse.ArgumentParser()
250 spec.add_argument("filename")
251 spec.add_argument("-c", "--count", type=int)
252 spec.add_argument("-v", "--verbose",
253 action="store_true")
254
255 result = spec.parse_args(sys.argv[1:])
256 print([result.filename, result.count, result.verbose])
257 '''
258
259 yb-capture (&r) {
260 for args in (argsCases) {
261 var args_str = args => join(" ")
262 echo "---------- $args_str ----------"
263 echo "\$ bin/ysh example.sh $args_str"
264 pp test_ (parseArgs(spec, args))
265
266 echo
267 echo "\$ python3 example.py $args_str"
268 python3 -c $argparse_py @args
269
270 echo
271 }
272 }
273
274 var expected = '''
275 ---------- -v --count 120 example.sh ----------
276 $ bin/ysh example.sh -v --count 120 example.sh
277 (Dict) {"verbose":true,"count":120,"file":"example.sh"}
278
279 $ python3 example.py -v --count 120 example.sh
280 ['example.sh', 120, True]
281
282 ---------- -v --count 120 example.sh -v ----------
283 $ bin/ysh example.sh -v --count 120 example.sh -v
284 (Dict) {"verbose":true,"count":120,"file":"example.sh"}
285
286 $ python3 example.py -v --count 120 example.sh -v
287 ['example.sh', 120, True]
288
289 ---------- -v --count 120 example.sh -v --count 150 ----------
290 $ bin/ysh example.sh -v --count 120 example.sh -v --count 150
291 (Dict) {"verbose":true,"count":150,"file":"example.sh"}
292
293 $ python3 example.py -v --count 120 example.sh -v --count 150
294 ['example.sh', 150, True]
295
296 '''
297
298 # This is acceptable, but the diff could look nicer and more precise
299 diff -u <(echo $expected) <(echo $[r.stdout])
300 #assert [expected === r.stdout]
301}
302
303if is-main {
304 byo-maybe-run
305}