UnknownSec Bypass
403
:
/
lib
/
python3
/
dist-packages
/
twisted
/
python
/
test
/ [
drwxr-xr-x
]
Menu
Upload
Mass depes
Mass delete
Terminal
Info server
About
name :
test_shellcomp.py
# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Test cases for twisted.python._shellcomp """ from __future__ import division, absolute_import import sys from io import BytesIO from twisted.trial import unittest from twisted.python import _shellcomp, usage, reflect from twisted.python.usage import Completions, Completer, CompleteFiles from twisted.python.usage import CompleteList class ZshScriptTestMeta(type): """ Metaclass of ZshScriptTestMixin. """ def __new__(cls, name, bases, attrs): def makeTest(cmdName, optionsFQPN): def runTest(self): return test_genZshFunction(self, cmdName, optionsFQPN) return runTest # add test_ methods to the class for each script # we are testing. if 'generateFor' in attrs: for cmdName, optionsFQPN in attrs['generateFor']: test = makeTest(cmdName, optionsFQPN) attrs['test_genZshFunction_' + cmdName] = test return type.__new__(cls, name, bases, attrs) class ZshScriptTestMixin(object): """ Integration test helper to show that C{usage.Options} classes can have zsh completion functions generated for them without raising errors. In your subclasses set a class variable like so: # | cmd name | Fully Qualified Python Name of Options class | # generateFor = [('conch', 'twisted.conch.scripts.conch.ClientOptions'), ('twistd', 'twisted.scripts.twistd.ServerOptions'), ] Each package that contains Twisted scripts should contain one TestCase subclass which also inherits from this mixin, and contains a C{generateFor} list appropriate for the scripts in that package. """ __metaclass__ = ZshScriptTestMeta def test_genZshFunction(self, cmdName, optionsFQPN): """ Generate completion functions for given twisted command - no errors should be raised @type cmdName: C{str} @param cmdName: The name of the command-line utility e.g. 'twistd' @type optionsFQPN: C{str} @param optionsFQPN: The Fully Qualified Python Name of the C{Options} class to be tested. """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) # some scripts won't import or instantiate because of missing # dependencies (pyOpenSSL, etc) so we have to skip them. try: o = reflect.namedAny(optionsFQPN)() except Exception as e: raise unittest.SkipTest("Couldn't import or instantiate " "Options class: %s" % (e,)) try: o.parseOptions(["", "--_shell-completion", "zsh:2"]) except ImportError as e: # this can happen for commands which don't have all # the necessary dependencies installed. skip test. # skip raise unittest.SkipTest("ImportError calling parseOptions(): %s", (e,)) except SystemExit: pass # expected else: self.fail('SystemExit not raised') outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) outputFile.seek(0) outputFile.truncate() # now, if it has sub commands, we have to test those too if hasattr(o, 'subCommands'): for (cmd, short, parser, doc) in o.subCommands: try: o.parseOptions([cmd, "", "--_shell-completion", "zsh:3"]) except ImportError as e: # this can happen for commands which don't have all # the necessary dependencies installed. skip test. raise unittest.SkipTest("ImportError calling parseOptions() " "on subcommand: %s", (e,)) except SystemExit: pass # expected else: self.fail('SystemExit not raised') outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) outputFile.seek(0) outputFile.truncate() # flushed because we don't want DeprecationWarnings to be printed when # running these test cases. self.flushWarnings() class ZshTests(unittest.TestCase): """ Tests for zsh completion code """ def test_accumulateMetadata(self): """ Are `compData' attributes you can place on Options classes picked up correctly? """ opts = FighterAceExtendedOptions() ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', BytesIO()) descriptions = FighterAceOptions.compData.descriptions.copy() descriptions.update(FighterAceExtendedOptions.compData.descriptions) self.assertEqual(ag.descriptions, descriptions) self.assertEqual(ag.multiUse, set(FighterAceOptions.compData.multiUse)) self.assertEqual(ag.mutuallyExclusive, FighterAceOptions.compData.mutuallyExclusive) optActions = FighterAceOptions.compData.optActions.copy() optActions.update(FighterAceExtendedOptions.compData.optActions) self.assertEqual(ag.optActions, optActions) self.assertEqual(ag.extraActions, FighterAceOptions.compData.extraActions) def test_mutuallyExclusiveCornerCase(self): """ Exercise a corner-case of ZshArgumentsGenerator.makeExcludesDict() where the long option name already exists in the `excludes` dict being built. """ class OddFighterAceOptions(FighterAceExtendedOptions): # since "fokker", etc, are already defined as mutually- # exclusive on the super-class, defining them again here forces # the corner-case to be exercised. optFlags = [['anatra', None, 'Select the Anatra DS as your dogfighter aircraft']] compData = Completions( mutuallyExclusive=[['anatra', 'fokker', 'albatros', 'spad', 'bristol']]) opts = OddFighterAceOptions() ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', BytesIO()) expected = { 'albatros': set(['anatra', 'b', 'bristol', 'f', 'fokker', 's', 'spad']), 'anatra': set(['a', 'albatros', 'b', 'bristol', 'f', 'fokker', 's', 'spad']), 'bristol': set(['a', 'albatros', 'anatra', 'f', 'fokker', 's', 'spad']), 'fokker': set(['a', 'albatros', 'anatra', 'b', 'bristol', 's', 'spad']), 'spad': set(['a', 'albatros', 'anatra', 'b', 'bristol', 'f', 'fokker'])} self.assertEqual(ag.excludes, expected) def test_accumulateAdditionalOptions(self): """ We pick up options that are only defined by having an appropriately named method on your Options class, e.g. def opt_foo(self, foo) """ opts = FighterAceExtendedOptions() ag = _shellcomp.ZshArgumentsGenerator(opts, 'ace', BytesIO()) self.assertIn('nocrash', ag.flagNameToDefinition) self.assertIn('nocrash', ag.allOptionsNameToDefinition) self.assertIn('difficulty', ag.paramNameToDefinition) self.assertIn('difficulty', ag.allOptionsNameToDefinition) def test_verifyZshNames(self): """ Using a parameter/flag name that doesn't exist will raise an error """ class TmpOptions(FighterAceExtendedOptions): # Note typo of detail compData = Completions(optActions={'detaill' : None}) self.assertRaises(ValueError, _shellcomp.ZshArgumentsGenerator, TmpOptions(), 'ace', BytesIO()) class TmpOptions2(FighterAceExtendedOptions): # Note that 'foo' and 'bar' are not real option # names defined in this class compData = Completions( mutuallyExclusive=[("foo", "bar")]) self.assertRaises(ValueError, _shellcomp.ZshArgumentsGenerator, TmpOptions2(), 'ace', BytesIO()) def test_zshCode(self): """ Generate a completion function, and test the textual output against a known correct output """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) self.patch(sys, 'argv', ["silly", "", "--_shell-completion", "zsh:2"]) opts = SimpleProgOptions() self.assertRaises(SystemExit, opts.parseOptions) self.assertEqual(testOutput1, outputFile.getvalue()) def test_zshCodeWithSubs(self): """ Generate a completion function with subcommands, and test the textual output against a known correct output """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) self.patch(sys, 'argv', ["silly2", "", "--_shell-completion", "zsh:2"]) opts = SimpleProgWithSubcommands() self.assertRaises(SystemExit, opts.parseOptions) self.assertEqual(testOutput2, outputFile.getvalue()) def test_incompleteCommandLine(self): """ Completion still happens even if a command-line is given that would normally throw UsageError. """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) opts = FighterAceOptions() self.assertRaises(SystemExit, opts.parseOptions, ["--fokker", "server", "--unknown-option", "--unknown-option2", "--_shell-completion", "zsh:5"]) outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) def test_incompleteCommandLine_case2(self): """ Completion still happens even if a command-line is given that would normally throw UsageError. The existence of --unknown-option prior to the subcommand will break subcommand detection... but we complete anyway """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) opts = FighterAceOptions() self.assertRaises(SystemExit, opts.parseOptions, ["--fokker", "--unknown-option", "server", "--list-server", "--_shell-completion", "zsh:5"]) outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) outputFile.seek(0) outputFile.truncate() def test_incompleteCommandLine_case3(self): """ Completion still happens even if a command-line is given that would normally throw UsageError. Break subcommand detection in a different way by providing an invalid subcommand name. """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) opts = FighterAceOptions() self.assertRaises(SystemExit, opts.parseOptions, ["--fokker", "unknown-subcommand", "--list-server", "--_shell-completion", "zsh:4"]) outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) def test_skipSubcommandList(self): """ Ensure the optimization which skips building the subcommand list under certain conditions isn't broken. """ outputFile = BytesIO() self.patch(usage.Options, '_shellCompFile', outputFile) opts = FighterAceOptions() self.assertRaises(SystemExit, opts.parseOptions, ["--alba", "--_shell-completion", "zsh:2"]) outputFile.seek(0) # test that we got some output self.assertEqual(1, len(outputFile.read(1))) def test_poorlyDescribedOptMethod(self): """ Test corner case fetching an option description from a method docstring """ opts = FighterAceOptions() argGen = _shellcomp.ZshArgumentsGenerator(opts, 'ace', None) descr = argGen.getDescription('silly') # docstring for opt_silly is useless so it should just use the # option name as the description self.assertEqual(descr, 'silly') def test_brokenActions(self): """ A C{Completer} with repeat=True may only be used as the last item in the extraActions list. """ class BrokenActions(usage.Options): compData = usage.Completions( extraActions=[usage.Completer(repeat=True), usage.Completer()] ) outputFile = BytesIO() opts = BrokenActions() self.patch(opts, '_shellCompFile', outputFile) self.assertRaises(ValueError, opts.parseOptions, ["", "--_shell-completion", "zsh:2"]) def test_optMethodsDontOverride(self): """ opt_* methods on Options classes should not override the data provided in optFlags or optParameters. """ class Options(usage.Options): optFlags = [['flag', 'f', 'A flag']] optParameters = [['param', 'p', None, 'A param']] def opt_flag(self): """ junk description """ def opt_param(self, param): """ junk description """ opts = Options() argGen = _shellcomp.ZshArgumentsGenerator(opts, 'ace', None) self.assertEqual(argGen.getDescription('flag'), 'A flag') self.assertEqual(argGen.getDescription('param'), 'A param') class EscapeTests(unittest.TestCase): def test_escape(self): """ Verify _shellcomp.escape() function """ esc = _shellcomp.escape test = "$" self.assertEqual(esc(test), "'$'") test = 'A--\'$"\\`--B' self.assertEqual(esc(test), '"A--\'\\$\\"\\\\\\`--B"') class CompleterNotImplementedTests(unittest.TestCase): """ Test that using an unknown shell constant with SubcommandAction raises NotImplementedError The other Completer() subclasses are tested in test_usage.py """ def test_unknownShell(self): """ Using an unknown shellType should raise NotImplementedError """ action = _shellcomp.SubcommandAction() self.assertRaises(NotImplementedError, action._shellCode, None, "bad_shell_type") class FighterAceServerOptions(usage.Options): """ Options for FighterAce 'server' subcommand """ optFlags = [['list-server', None, 'List this server with the online FighterAce network']] optParameters = [['packets-per-second', None, 'Number of update packets to send per second', '20']] class FighterAceOptions(usage.Options): """ Command-line options for an imaginary `Fighter Ace` game """ optFlags = [['fokker', 'f', 'Select the Fokker Dr.I as your dogfighter aircraft'], ['albatros', 'a', 'Select the Albatros D-III as your dogfighter aircraft'], ['spad', 's', 'Select the SPAD S.VII as your dogfighter aircraft'], ['bristol', 'b', 'Select the Bristol Scout as your dogfighter aircraft'], ['physics', 'p', 'Enable secret Twisted physics engine'], ['jam', 'j', 'Enable a small chance that your machine guns will jam!'], ['verbose', 'v', 'Verbose logging (may be specified more than once)'], ] optParameters = [['pilot-name', None, "What's your name, Ace?", 'Manfred von Richthofen'], ['detail', 'd', 'Select the level of rendering detail (1-5)', '3'], ] subCommands = [['server', None, FighterAceServerOptions, 'Start FighterAce game-server.'], ] compData = Completions( descriptions={'physics' : 'Twisted-Physics', 'detail' : 'Rendering detail level'}, multiUse=['verbose'], mutuallyExclusive=[['fokker', 'albatros', 'spad', 'bristol']], optActions={'detail' : CompleteList(['1' '2' '3' '4' '5'])}, extraActions=[CompleteFiles(descr='saved game file to load')] ) def opt_silly(self): # A silly option which nobody can explain """ """ class FighterAceExtendedOptions(FighterAceOptions): """ Extend the options and zsh metadata provided by FighterAceOptions. _shellcomp must accumulate options and metadata from all classes in the hiearchy so this is important to test. """ optFlags = [['no-stalls', None, 'Turn off the ability to stall your aircraft']] optParameters = [['reality-level', None, 'Select the level of physics reality (1-5)', '5']] compData = Completions( descriptions={'no-stalls' : 'Can\'t stall your plane'}, optActions={'reality-level' : Completer(descr='Physics reality level')} ) def opt_nocrash(self): """ Select that you can't crash your plane """ def opt_difficulty(self, difficulty): """ How tough are you? (1-10) """ def _accuracyAction(): # add tick marks just to exercise quoting return CompleteList(['1', '2', '3'], descr='Accuracy\'`?') class SimpleProgOptions(usage.Options): """ Command-line options for a `Silly` imaginary program """ optFlags = [['color', 'c', 'Turn on color output'], ['gray', 'g', 'Turn on gray-scale output'], ['verbose', 'v', 'Verbose logging (may be specified more than once)'], ] optParameters = [['optimization', None, '5', 'Select the level of optimization (1-5)'], ['accuracy', 'a', '3', 'Select the level of accuracy (1-3)'], ] compData = Completions( descriptions={'color' : 'Color on', 'optimization' : 'Optimization level'}, multiUse=['verbose'], mutuallyExclusive=[['color', 'gray']], optActions={'optimization' : CompleteList(['1', '2', '3', '4', '5'], descr='Optimization?'), 'accuracy' : _accuracyAction}, extraActions=[CompleteFiles(descr='output file')] ) def opt_X(self): """ usage.Options does not recognize single-letter opt_ methods """ class SimpleProgSub1(usage.Options): optFlags = [['sub-opt', 's', 'Sub Opt One']] class SimpleProgSub2(usage.Options): optFlags = [['sub-opt', 's', 'Sub Opt Two']] class SimpleProgWithSubcommands(SimpleProgOptions): optFlags = [['some-option'], ['other-option', 'o']] optParameters = [['some-param'], ['other-param', 'p'], ['another-param', 'P', 'Yet Another Param']] subCommands = [ ['sub1', None, SimpleProgSub1, 'Sub Command 1'], ['sub2', None, SimpleProgSub2, 'Sub Command 2']] testOutput1 = b"""#compdef silly _arguments -s -A "-*" \\ ':output file (*):_files -g "*"' \\ "(--accuracy)-a[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ "(-a)--accuracy=[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ '(--color --gray -g)-c[Color on]' \\ '(--gray -c -g)--color[Color on]' \\ '(--color --gray -c)-g[Turn on gray-scale output]' \\ '(--color -c -g)--gray[Turn on gray-scale output]' \\ '--help[Display this help and exit.]' \\ '--optimization=[Optimization level]:Optimization?:(1 2 3 4 5)' \\ '*-v[Verbose logging (may be specified more than once)]' \\ '*--verbose[Verbose logging (may be specified more than once)]' \\ '--version[Display Twisted version and exit.]' \\ && return 0 """ # with sub-commands testOutput2 = b"""#compdef silly2 _arguments -s -A "-*" \\ '*::subcmd:->subcmd' \\ ':output file (*):_files -g "*"' \\ "(--accuracy)-a[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ "(-a)--accuracy=[Select the level of accuracy (1-3)]:Accuracy'\`?:(1 2 3)" \\ '(--another-param)-P[another-param]:another-param:_files' \\ '(-P)--another-param=[another-param]:another-param:_files' \\ '(--color --gray -g)-c[Color on]' \\ '(--gray -c -g)--color[Color on]' \\ '(--color --gray -c)-g[Turn on gray-scale output]' \\ '(--color -c -g)--gray[Turn on gray-scale output]' \\ '--help[Display this help and exit.]' \\ '--optimization=[Optimization level]:Optimization?:(1 2 3 4 5)' \\ '(--other-option)-o[other-option]' \\ '(-o)--other-option[other-option]' \\ '(--other-param)-p[other-param]:other-param:_files' \\ '(-p)--other-param=[other-param]:other-param:_files' \\ '--some-option[some-option]' \\ '--some-param=[some-param]:some-param:_files' \\ '*-v[Verbose logging (may be specified more than once)]' \\ '*--verbose[Verbose logging (may be specified more than once)]' \\ '--version[Display Twisted version and exit.]' \\ && return 0 local _zsh_subcmds_array _zsh_subcmds_array=( "sub1:Sub Command 1" "sub2:Sub Command 2" ) _describe "sub-command" _zsh_subcmds_array """
Copyright © 2025 - UnknownSec