1 #!/usr/bin/env python2
2 """
3 args_test.py: Tests for args.py
4 """
5
6 import unittest
7
8 from _devbuild.gen.runtime_asdl import cmd_value, value
9 from _devbuild.gen.syntax_asdl import loc, loc_t
10 from core import error
11 from frontend import flag_spec
12 from frontend import args # module under test
13
14 from typing import Tuple
15
16
17 def _MakeBuiltinArgv(argv):
18 """Different than test_lib.MakeBuiltinArgv()"""
19 argv = [''] + argv # add dummy since arg_vec includes argv[0]
20 # no location info
21 missing = loc.Missing # type: loc_t
22 return cmd_value.Argv(argv, [missing] * len(argv), None)
23
24
25 def _MakeReader(argv):
26 cmd_val = _MakeBuiltinArgv(argv)
27 arg_r = args.Reader(cmd_val.argv, locs=cmd_val.arg_locs)
28 arg_r.Next()
29 return arg_r
30
31
32 def _ParseCmdVal(spec, cmd_val):
33 # type: (cmd_value.Argv) -> Tuple[args._Attributes, int]
34 """For testing only."""
35 arg_r = args.Reader(cmd_val.argv, locs=cmd_val.arg_locs)
36 arg_r.Next() # move past the builtin name
37 return args.Parse(spec, arg_r), arg_r.i
38
39
40 class ArgsTest(unittest.TestCase):
41 def testFlagSpecAndMore(self):
42 s = flag_spec._FlagSpecAndMore()
43 s.ShortFlag('-c', args.String)
44 s.ShortFlag('-i', args.String)
45
46 s.LongFlag('--help')
47 s.LongFlag('--rcfile', args.String)
48 s.LongFlag('--rcdir', args.String)
49 s.LongFlag('--norc')
50
51 s.LongFlag('--ast-format', ['text', 'html'])
52
53 s.InitOptions()
54 s.Option('e', 'errexit')
55 s.Option('u', 'nounset')
56 s.Option(None, 'pipefail')
57
58 # don't parse args afterward
59 arg_r = args.Reader(
60 ['-c', 'echo hi', '-e', '-o', 'nounset', 'foo', '--help'])
61 arg = args.ParseMore(s, arg_r)
62
63 self.assertEqual(['foo', '--help'], arg_r.Rest())
64 self.assertEqual('echo hi', arg.attrs['c'].s)
65 self.assertEqual(False, arg.attrs['help'].b)
66 self.assertEqual(value.Undef, arg.attrs['i'])
67
68 self.assertEqual([('errexit', True), ('nounset', True)],
69 arg.opt_changes)
70
71 arg_r = args.Reader(['+e', '+o', 'nounset', '-o', 'pipefail', 'foo'])
72 arg = args.ParseMore(s, arg_r)
73
74 self.assertEqual(['foo'], arg_r.Rest())
75 self.assertEqual(value.Undef, arg.attrs['i'])
76 self.assertEqual([('errexit', False), ('nounset', False),
77 ('pipefail', True)], arg.opt_changes)
78
79 arg_r = args.Reader([
80 '-c', 'echo hi', '--help', '--rcfile', 'bashrc', '--rcdir',
81 'bashrcdir'
82 ])
83 arg = args.ParseMore(s, arg_r)
84 self.assertEqual('echo hi', arg.attrs['c'].s)
85 self.assertEqual(True, arg.attrs['help'].b)
86 self.assertEqual('bashrc', arg.attrs['rcfile'].s)
87 self.assertEqual('bashrcdir', arg.attrs['rcdir'].s)
88
89 # This is an odd syntax!
90 arg_r = args.Reader(['-euo', 'pipefail'])
91 arg = args.ParseMore(s, arg_r)
92 self.assertEqual([('errexit', True), ('nounset', True),
93 ('pipefail', True)], arg.opt_changes)
94 self.assertEqual(2, arg_r.i)
95
96 # Even weirder!
97 arg_r = args.Reader(['+oeu', 'pipefail'])
98 arg = args.ParseMore(s, arg_r)
99 self.assertEqual([('pipefail', False), ('errexit', False),
100 ('nounset', False)], arg.opt_changes)
101 self.assertEqual(2, arg_r.i)
102
103 # Even weirder!
104 arg_r = args.Reader(['+oo', 'pipefail', 'errexit'])
105 arg = args.ParseMore(s, arg_r)
106 self.assertEqual([('pipefail', False), ('errexit', False)],
107 arg.opt_changes)
108 self.assertEqual(3, arg_r.i)
109
110 # Now this is an arg. Gah.
111 arg_r = args.Reader(['+o', 'pipefail', 'errexit'])
112 arg = args.ParseMore(s, arg_r)
113 self.assertEqual([('pipefail', False)], arg.opt_changes)
114 self.assertEqual(['errexit'], arg_r.Rest())
115
116 # NOTE: 'set -ooo' and 'set -o -o -o' bash runs 'set -o' three times!
117 # We're not going to replicate that silly behavior.
118
119 def testChoices(self):
120 s = flag_spec._FlagSpecAndMore()
121 s.LongFlag('--ast-format', ['text', 'html'])
122
123 arg_r = args.Reader(['--ast-format', 'text'])
124 arg = args.ParseMore(s, arg_r)
125 self.assertEqual('text', arg.attrs['ast_format'].s)
126
127 self.assertRaises(error.Usage, args.Parse, s,
128 args.Reader(['--ast-format', 'oops']))
129
130 def testFlagSpec(self):
131 s = flag_spec._FlagSpec()
132 s.ShortFlag('-f')
133 s.ShortFlag('-n')
134 s.ShortFlag('-d', args.String) # delimiter
135
136 # like declare +rx
137 s.PlusFlag('r')
138 s.PlusFlag('x')
139
140 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-f', 'foo', 'bar']))
141 self.assertEqual(1, i - 1)
142 self.assertEqual(True, arg.attrs['f'].b)
143 #self.assertEqual(False, arg.n)
144 self.assertEqual(False, arg.attrs['n'].b)
145
146 self.assertRaises(error.Usage, _ParseCmdVal, s,
147 _MakeBuiltinArgv(['-f', '-d']))
148
149 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-d', ' ', 'foo']))
150 self.assertEqual(2, i - 1)
151 self.assertEqual(' ', arg.attrs['d'].s)
152
153 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-d,', 'foo']))
154 self.assertEqual(1, i - 1)
155 self.assertEqual(',', arg.attrs['d'].s)
156 #self.assertEqual(False, arg.r)
157 self.assertEqual(value.Undef, arg.attrs['r'])
158
159 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-d,', '-r', '-x']))
160 self.assertEqual(4, i)
161 self.assertEqual(',', arg.attrs['d'].s)
162 self.assertEqual('-', arg.attrs['r'].s)
163 self.assertEqual('-', arg.attrs['x'].s)
164
165 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-d,', '+rx']))
166 self.assertEqual(3, i)
167 self.assertEqual(',', arg.attrs['d'].s)
168 self.assertEqual('+', arg.attrs['r'].s)
169 self.assertEqual('+', arg.attrs['x'].s)
170
171 def testReadFlagSpec(self):
172 s = flag_spec._FlagSpec()
173 s.ShortFlag('-r') # no backslash escapes
174 s.ShortFlag('-t', args.Float) # timeout
175 s.ShortFlag('-p', args.String) # prompt string
176
177 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-r', 'foo']))
178 self.assertEqual(True, arg.attrs['r'].b)
179 self.assertEqual(1, i - 1)
180
181 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-p', '>']))
182 self.assertEqual(False, arg.attrs['r'].b)
183 self.assertEqual('>', arg.attrs['p'].s)
184 self.assertEqual(2, i - 1)
185
186 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-rp', '>']))
187 self.assertEqual(True, arg.attrs['r'].b)
188 self.assertEqual('>', arg.attrs['p'].s)
189 self.assertEqual(2, i - 1)
190
191 # REALLY ANNOYING: The first r is a flag, the second R is the prompt! Only
192 # works in that order
193 # Does that mean anything with an arity consumes the rest?
194 # read -p line
195 #
196 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(['-rpr']))
197 self.assertEqual(True, arg.attrs['r'].b)
198 self.assertEqual('r', arg.attrs['p'].s)
199 self.assertEqual(1, i - 1)
200
201 argv = ['-t1.5', '>']
202 arg, i = _ParseCmdVal(s, _MakeBuiltinArgv(argv))
203 self.assertEqual(1.5, arg.attrs['t'].f)
204 self.assertEqual(1, i - 1)
205
206 # Invalid flag 'z'
207 self.assertRaises(error.Usage, _ParseCmdVal, s,
208 _MakeBuiltinArgv(['-rz']))
209
210 def testParseLikeEcho(self):
211 s = flag_spec._FlagSpec()
212 s.ShortFlag('-e') # no backslash escapes
213 s.ShortFlag('-n')
214
215 arg_r = _MakeReader(['-e', '-n', 'foo'])
216 arg = args.ParseLikeEcho(s, arg_r)
217 self.assertEqual(True, arg.attrs['e'].b)
218 self.assertEqual(True, arg.attrs['n'].b)
219 self.assertEqual(3, arg_r.i)
220
221 arg_r = _MakeReader(['-en', 'foo'])
222 arg = args.ParseLikeEcho(s, arg_r)
223 self.assertEqual(True, arg.attrs['e'].b)
224 self.assertEqual(True, arg.attrs['n'].b)
225 self.assertEqual(2, arg_r.i)
226
227 arg_r = _MakeReader(['-ez', 'foo'])
228 arg = args.ParseLikeEcho(s, arg_r)
229 self.assertEqual(False, arg.attrs['e'].b)
230 self.assertEqual(False, arg.attrs['n'].b)
231 self.assertEqual(1, arg_r.i)
232
233
234 if __name__ == '__main__':
235 unittest.main()