Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / test / test_usage.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Tests for L{twisted.python.usage}, a command line option parsing library.
6 """
7
8 from twisted.trial import unittest
9 from twisted.python import usage
10
11
12 class WellBehaved(usage.Options):
13     optParameters = [['long', 'w', 'default', 'and a docstring'],
14                      ['another', 'n', 'no docstring'],
15                      ['longonly', None, 'noshort'],
16                      ['shortless', None, 'except',
17                       'this one got docstring'],
18                   ]
19     optFlags = [['aflag', 'f',
20                  """
21
22                  flagallicious docstringness for this here
23
24                  """],
25                 ['flout', 'o'],
26                 ]
27
28     def opt_myflag(self):
29         self.opts['myflag'] = "PONY!"
30
31
32     def opt_myparam(self, value):
33         self.opts['myparam'] = "%s WITH A PONY!" % (value,)
34
35
36
37 class ParseCorrectnessTest(unittest.TestCase):
38     """
39     Test Options.parseArgs for correct values under good conditions.
40     """
41     def setUp(self):
42         """
43         Instantiate and parseOptions a well-behaved Options class.
44         """
45
46         self.niceArgV = ("--long Alpha -n Beta "
47                          "--shortless Gamma -f --myflag "
48                          "--myparam Tofu").split()
49
50         self.nice = WellBehaved()
51
52         self.nice.parseOptions(self.niceArgV)
53
54     def test_checkParameters(self):
55         """
56         Checking that parameters have correct values.
57         """
58         self.assertEqual(self.nice.opts['long'], "Alpha")
59         self.assertEqual(self.nice.opts['another'], "Beta")
60         self.assertEqual(self.nice.opts['longonly'], "noshort")
61         self.assertEqual(self.nice.opts['shortless'], "Gamma")
62
63     def test_checkFlags(self):
64         """
65         Checking that flags have correct values.
66         """
67         self.assertEqual(self.nice.opts['aflag'], 1)
68         self.assertEqual(self.nice.opts['flout'], 0)
69
70     def test_checkCustoms(self):
71         """
72         Checking that custom flags and parameters have correct values.
73         """
74         self.assertEqual(self.nice.opts['myflag'], "PONY!")
75         self.assertEqual(self.nice.opts['myparam'], "Tofu WITH A PONY!")
76
77
78
79 class TypedOptions(usage.Options):
80     optParameters = [
81         ['fooint', None, 392, 'Foo int', int],
82         ['foofloat', None, 4.23, 'Foo float', float],
83         ['eggint', None, None, 'Egg int without default', int],
84         ['eggfloat', None, None, 'Egg float without default', float],
85     ]
86
87     def opt_under_score(self, value):
88         """
89         This option has an underscore in its name to exercise the _ to -
90         translation.
91         """
92         self.underscoreValue = value
93     opt_u = opt_under_score
94
95
96
97 class TypedTestCase(unittest.TestCase):
98     """
99     Test Options.parseArgs for options with forced types.
100     """
101     def setUp(self):
102         self.usage = TypedOptions()
103
104     def test_defaultValues(self):
105         """
106         Test parsing of default values.
107         """
108         argV = []
109         self.usage.parseOptions(argV)
110         self.assertEqual(self.usage.opts['fooint'], 392)
111         self.assert_(isinstance(self.usage.opts['fooint'], int))
112         self.assertEqual(self.usage.opts['foofloat'], 4.23)
113         self.assert_(isinstance(self.usage.opts['foofloat'], float))
114         self.assertEqual(self.usage.opts['eggint'], None)
115         self.assertEqual(self.usage.opts['eggfloat'], None)
116
117
118     def test_parsingValues(self):
119         """
120         Test basic parsing of int and float values.
121         """
122         argV = ("--fooint 912 --foofloat -823.1 "
123                 "--eggint 32 --eggfloat 21").split()
124         self.usage.parseOptions(argV)
125         self.assertEqual(self.usage.opts['fooint'], 912)
126         self.assert_(isinstance(self.usage.opts['fooint'], int))
127         self.assertEqual(self.usage.opts['foofloat'], -823.1)
128         self.assert_(isinstance(self.usage.opts['foofloat'], float))
129         self.assertEqual(self.usage.opts['eggint'], 32)
130         self.assert_(isinstance(self.usage.opts['eggint'], int))
131         self.assertEqual(self.usage.opts['eggfloat'], 21.)
132         self.assert_(isinstance(self.usage.opts['eggfloat'], float))
133
134
135     def test_underscoreOption(self):
136         """
137         A dash in an option name is translated to an underscore before being
138         dispatched to a handler.
139         """
140         self.usage.parseOptions(['--under-score', 'foo'])
141         self.assertEqual(self.usage.underscoreValue, 'foo')
142
143
144     def test_underscoreOptionAlias(self):
145         """
146         An option name with a dash in it can have an alias.
147         """
148         self.usage.parseOptions(['-u', 'bar'])
149         self.assertEqual(self.usage.underscoreValue, 'bar')
150
151
152     def test_invalidValues(self):
153         """
154         Check that passing wrong values raises an error.
155         """
156         argV = "--fooint egg".split()
157         self.assertRaises(usage.UsageError, self.usage.parseOptions, argV)
158
159
160
161 class WrongTypedOptions(usage.Options):
162     optParameters = [
163         ['barwrong', None, None, 'Bar with wrong coerce', 'he']
164     ]
165
166
167 class WeirdCallableOptions(usage.Options):
168     def _bar(value):
169         raise RuntimeError("Ouch")
170     def _foo(value):
171         raise ValueError("Yay")
172     optParameters = [
173         ['barwrong', None, None, 'Bar with strange callable', _bar],
174         ['foowrong', None, None, 'Foo with strange callable', _foo]
175     ]
176
177
178 class WrongTypedTestCase(unittest.TestCase):
179     """
180     Test Options.parseArgs for wrong coerce options.
181     """
182     def test_nonCallable(self):
183         """
184         Check that using a non callable type fails.
185         """
186         us =  WrongTypedOptions()
187         argV = "--barwrong egg".split()
188         self.assertRaises(TypeError, us.parseOptions, argV)
189
190     def test_notCalledInDefault(self):
191         """
192         Test that the coerce functions are not called if no values are
193         provided.
194         """
195         us = WeirdCallableOptions()
196         argV = []
197         us.parseOptions(argV)
198
199     def test_weirdCallable(self):
200         """
201         Test what happens when coerce functions raise errors.
202         """
203         us = WeirdCallableOptions()
204         argV = "--foowrong blah".split()
205         # ValueError is swallowed as UsageError
206         e = self.assertRaises(usage.UsageError, us.parseOptions, argV)
207         self.assertEqual(str(e), "Parameter type enforcement failed: Yay")
208
209         us = WeirdCallableOptions()
210         argV = "--barwrong blah".split()
211         # RuntimeError is not swallowed
212         self.assertRaises(RuntimeError, us.parseOptions, argV)
213
214
215 class OutputTest(unittest.TestCase):
216     def test_uppercasing(self):
217         """
218         Error output case adjustment does not mangle options
219         """
220         opt = WellBehaved()
221         e = self.assertRaises(usage.UsageError,
222                               opt.parseOptions, ['-Z'])
223         self.assertEqual(str(e), 'option -Z not recognized')
224
225
226 class InquisitionOptions(usage.Options):
227     optFlags = [
228         ('expect', 'e'),
229         ]
230     optParameters = [
231         ('torture-device', 't',
232          'comfy-chair',
233          'set preferred torture device'),
234         ]
235
236
237 class HolyQuestOptions(usage.Options):
238     optFlags = [('horseback', 'h',
239                  'use a horse'),
240                 ('for-grail', 'g'),
241                 ]
242
243
244 class SubCommandOptions(usage.Options):
245     optFlags = [('europian-swallow', None,
246                  'set default swallow type to Europian'),
247                 ]
248     subCommands = [
249         ('inquisition', 'inquest', InquisitionOptions,
250             'Perform an inquisition'),
251         ('holyquest', 'quest', HolyQuestOptions,
252             'Embark upon a holy quest'),
253         ]
254
255
256 class SubCommandTest(unittest.TestCase):
257
258     def test_simpleSubcommand(self):
259         o = SubCommandOptions()
260         o.parseOptions(['--europian-swallow', 'inquisition'])
261         self.assertEqual(o['europian-swallow'], True)
262         self.assertEqual(o.subCommand, 'inquisition')
263         self.failUnless(isinstance(o.subOptions, InquisitionOptions))
264         self.assertEqual(o.subOptions['expect'], False)
265         self.assertEqual(o.subOptions['torture-device'], 'comfy-chair')
266
267     def test_subcommandWithFlagsAndOptions(self):
268         o = SubCommandOptions()
269         o.parseOptions(['inquisition', '--expect', '--torture-device=feather'])
270         self.assertEqual(o['europian-swallow'], False)
271         self.assertEqual(o.subCommand, 'inquisition')
272         self.failUnless(isinstance(o.subOptions, InquisitionOptions))
273         self.assertEqual(o.subOptions['expect'], True)
274         self.assertEqual(o.subOptions['torture-device'], 'feather')
275
276     def test_subcommandAliasWithFlagsAndOptions(self):
277         o = SubCommandOptions()
278         o.parseOptions(['inquest', '--expect', '--torture-device=feather'])
279         self.assertEqual(o['europian-swallow'], False)
280         self.assertEqual(o.subCommand, 'inquisition')
281         self.failUnless(isinstance(o.subOptions, InquisitionOptions))
282         self.assertEqual(o.subOptions['expect'], True)
283         self.assertEqual(o.subOptions['torture-device'], 'feather')
284
285     def test_anotherSubcommandWithFlagsAndOptions(self):
286         o = SubCommandOptions()
287         o.parseOptions(['holyquest', '--for-grail'])
288         self.assertEqual(o['europian-swallow'], False)
289         self.assertEqual(o.subCommand, 'holyquest')
290         self.failUnless(isinstance(o.subOptions, HolyQuestOptions))
291         self.assertEqual(o.subOptions['horseback'], False)
292         self.assertEqual(o.subOptions['for-grail'], True)
293
294     def test_noSubcommand(self):
295         o = SubCommandOptions()
296         o.parseOptions(['--europian-swallow'])
297         self.assertEqual(o['europian-swallow'], True)
298         self.assertEqual(o.subCommand, None)
299         self.failIf(hasattr(o, 'subOptions'))
300
301     def test_defaultSubcommand(self):
302         o = SubCommandOptions()
303         o.defaultSubCommand = 'inquest'
304         o.parseOptions(['--europian-swallow'])
305         self.assertEqual(o['europian-swallow'], True)
306         self.assertEqual(o.subCommand, 'inquisition')
307         self.failUnless(isinstance(o.subOptions, InquisitionOptions))
308         self.assertEqual(o.subOptions['expect'], False)
309         self.assertEqual(o.subOptions['torture-device'], 'comfy-chair')
310
311     def test_subCommandParseOptionsHasParent(self):
312         class SubOpt(usage.Options):
313             def parseOptions(self, *a, **kw):
314                 self.sawParent = self.parent
315                 usage.Options.parseOptions(self, *a, **kw)
316         class Opt(usage.Options):
317             subCommands = [
318                 ('foo', 'f', SubOpt, 'bar'),
319                 ]
320         o = Opt()
321         o.parseOptions(['foo'])
322         self.failUnless(hasattr(o.subOptions, 'sawParent'))
323         self.assertEqual(o.subOptions.sawParent , o)
324
325     def test_subCommandInTwoPlaces(self):
326         """
327         The .parent pointer is correct even when the same Options class is
328         used twice.
329         """
330         class SubOpt(usage.Options):
331             pass
332         class OptFoo(usage.Options):
333             subCommands = [
334                 ('foo', 'f', SubOpt, 'quux'),
335                 ]
336         class OptBar(usage.Options):
337             subCommands = [
338                 ('bar', 'b', SubOpt, 'quux'),
339                 ]
340         oFoo = OptFoo()
341         oFoo.parseOptions(['foo'])
342         oBar=OptBar()
343         oBar.parseOptions(['bar'])
344         self.failUnless(hasattr(oFoo.subOptions, 'parent'))
345         self.failUnless(hasattr(oBar.subOptions, 'parent'))
346         self.failUnlessIdentical(oFoo.subOptions.parent, oFoo)
347         self.failUnlessIdentical(oBar.subOptions.parent, oBar)
348
349
350 class HelpStringTest(unittest.TestCase):
351     def setUp(self):
352         """
353         Instantiate a well-behaved Options class.
354         """
355
356         self.niceArgV = ("--long Alpha -n Beta "
357                          "--shortless Gamma -f --myflag "
358                          "--myparam Tofu").split()
359
360         self.nice = WellBehaved()
361
362     def test_noGoBoom(self):
363         """
364         __str__ shouldn't go boom.
365         """
366         try:
367             self.nice.__str__()
368         except Exception, e:
369             self.fail(e)
370
371     def test_whitespaceStripFlagsAndParameters(self):
372         """
373         Extra whitespace in flag and parameters docs is stripped.
374         """
375         # We test this by making sure aflag and it's help string are on the
376         # same line.
377         lines = [s for s in str(self.nice).splitlines() if s.find("aflag")>=0]
378         self.failUnless(len(lines) > 0)
379         self.failUnless(lines[0].find("flagallicious") >= 0)
380
381
382 class PortCoerceTestCase(unittest.TestCase):
383     """
384     Test the behavior of L{usage.portCoerce}.
385     """
386     def test_validCoerce(self):
387         """
388         Test the answers with valid input.
389         """
390         self.assertEqual(0, usage.portCoerce("0"))
391         self.assertEqual(3210, usage.portCoerce("3210"))
392         self.assertEqual(65535, usage.portCoerce("65535"))
393
394     def test_errorCoerce(self):
395         """
396         Test error path.
397         """
398         self.assertRaises(ValueError, usage.portCoerce, "")
399         self.assertRaises(ValueError, usage.portCoerce, "-21")
400         self.assertRaises(ValueError, usage.portCoerce, "212189")
401         self.assertRaises(ValueError, usage.portCoerce, "foo")
402
403
404
405 class ZshCompleterTestCase(unittest.TestCase):
406     """
407     Test the behavior of the various L{twisted.usage.Completer} classes
408     for producing output usable by zsh tab-completion system.
409     """
410     def test_completer(self):
411         """
412         Completer produces zsh shell-code that produces no completion matches.
413         """
414         c = usage.Completer()
415         got = c._shellCode('some-option', usage._ZSH)
416         self.assertEqual(got, ':some-option:')
417
418         c = usage.Completer(descr='some action', repeat=True)
419         got = c._shellCode('some-option', usage._ZSH)
420         self.assertEqual(got, '*:some action:')
421
422
423     def test_files(self):
424         """
425         CompleteFiles produces zsh shell-code that completes file names
426         according to a glob.
427         """
428         c = usage.CompleteFiles()
429         got = c._shellCode('some-option', usage._ZSH)
430         self.assertEqual(got, ':some-option (*):_files -g "*"')
431
432         c = usage.CompleteFiles('*.py')
433         got = c._shellCode('some-option', usage._ZSH)
434         self.assertEqual(got, ':some-option (*.py):_files -g "*.py"')
435
436         c = usage.CompleteFiles('*.py', descr="some action", repeat=True)
437         got = c._shellCode('some-option', usage._ZSH)
438         self.assertEqual(got, '*:some action (*.py):_files -g "*.py"')
439
440
441     def test_dirs(self):
442         """
443         CompleteDirs produces zsh shell-code that completes directory names.
444         """
445         c = usage.CompleteDirs()
446         got = c._shellCode('some-option', usage._ZSH)
447         self.assertEqual(got, ':some-option:_directories')
448
449         c = usage.CompleteDirs(descr="some action", repeat=True)
450         got = c._shellCode('some-option', usage._ZSH)
451         self.assertEqual(got, '*:some action:_directories')
452
453
454     def test_list(self):
455         """
456         CompleteList produces zsh shell-code that completes words from a fixed
457         list of possibilities.
458         """
459         c = usage.CompleteList('ABC')
460         got = c._shellCode('some-option', usage._ZSH)
461         self.assertEqual(got, ':some-option:(A B C)')
462
463         c = usage.CompleteList(['1', '2', '3'])
464         got = c._shellCode('some-option', usage._ZSH)
465         self.assertEqual(got, ':some-option:(1 2 3)')
466
467         c = usage.CompleteList(['1', '2', '3'], descr='some action',
468                                repeat=True)
469         got = c._shellCode('some-option', usage._ZSH)
470         self.assertEqual(got, '*:some action:(1 2 3)')
471
472
473     def test_multiList(self):
474         """
475         CompleteMultiList produces zsh shell-code that completes multiple
476         comma-separated words from a fixed list of possibilities.
477         """
478         c = usage.CompleteMultiList('ABC')
479         got = c._shellCode('some-option', usage._ZSH)
480         self.assertEqual(got, ':some-option:_values -s , \'some-option\' A B C')
481
482         c = usage.CompleteMultiList(['1','2','3'])
483         got = c._shellCode('some-option', usage._ZSH)
484         self.assertEqual(got, ':some-option:_values -s , \'some-option\' 1 2 3')
485
486         c = usage.CompleteMultiList(['1','2','3'], descr='some action',
487                                     repeat=True)
488         got = c._shellCode('some-option', usage._ZSH)
489         expected = '*:some action:_values -s , \'some action\' 1 2 3'
490         self.assertEqual(got, expected)
491
492
493     def test_usernames(self):
494         """
495         CompleteUsernames produces zsh shell-code that completes system
496         usernames.
497         """
498         c = usage.CompleteUsernames()
499         out = c._shellCode('some-option', usage._ZSH)
500         self.assertEqual(out, ':some-option:_users')
501
502         c = usage.CompleteUsernames(descr='some action', repeat=True)
503         out = c._shellCode('some-option', usage._ZSH)
504         self.assertEqual(out, '*:some action:_users')
505
506
507     def test_groups(self):
508         """
509         CompleteGroups produces zsh shell-code that completes system group
510         names.
511         """
512         c = usage.CompleteGroups()
513         out = c._shellCode('some-option', usage._ZSH)
514         self.assertEqual(out, ':group:_groups')
515
516         c = usage.CompleteGroups(descr='some action', repeat=True)
517         out = c._shellCode('some-option', usage._ZSH)
518         self.assertEqual(out, '*:some action:_groups')
519
520
521     def test_hostnames(self):
522         """
523         CompleteHostnames produces zsh shell-code that completes hostnames.
524         """
525         c = usage.CompleteHostnames()
526         out = c._shellCode('some-option', usage._ZSH)
527         self.assertEqual(out, ':some-option:_hosts')
528
529         c = usage.CompleteHostnames(descr='some action', repeat=True)
530         out = c._shellCode('some-option', usage._ZSH)
531         self.assertEqual(out, '*:some action:_hosts')
532
533
534     def test_userAtHost(self):
535         """
536         CompleteUserAtHost produces zsh shell-code that completes hostnames or
537         a word of the form <username>@<hostname>.
538         """
539         c = usage.CompleteUserAtHost()
540         out = c._shellCode('some-option', usage._ZSH)
541         self.assertTrue(out.startswith(':host | user@host:'))
542
543         c = usage.CompleteUserAtHost(descr='some action', repeat=True)
544         out = c._shellCode('some-option', usage._ZSH)
545         self.assertTrue(out.startswith('*:some action:'))
546
547
548     def test_netInterfaces(self):
549         """
550         CompleteNetInterfaces produces zsh shell-code that completes system
551         network interface names.
552         """
553         c = usage.CompleteNetInterfaces()
554         out = c._shellCode('some-option', usage._ZSH)
555         self.assertEqual(out, ':some-option:_net_interfaces')
556
557         c = usage.CompleteNetInterfaces(descr='some action', repeat=True)
558         out = c._shellCode('some-option', usage._ZSH)
559         self.assertEqual(out, '*:some action:_net_interfaces')
560
561
562
563 class CompleterNotImplementedTestCase(unittest.TestCase):
564     """
565     Using an unknown shell constant with the various Completer() classes
566     should raise NotImplementedError
567     """
568     def test_unknownShell(self):
569         """
570         Using an unknown shellType should raise NotImplementedError
571         """
572         classes = [usage.Completer, usage.CompleteFiles,
573                    usage.CompleteDirs, usage.CompleteList,
574                    usage.CompleteMultiList, usage.CompleteUsernames,
575                    usage.CompleteGroups, usage.CompleteHostnames,
576                    usage.CompleteUserAtHost, usage.CompleteNetInterfaces]
577
578         for cls in classes:
579             try:
580                 action = cls()
581             except:
582                 action = cls(None)
583             self.assertRaises(NotImplementedError, action._shellCode,
584                               None, "bad_shell_type")