1# -------------------------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for license information. 4# -------------------------------------------------------------------------------------------- 5 6import unittest 7try: 8 import mock 9except ImportError: 10 from unittest import mock 11 12import sys 13import argparse 14 15from knack.arguments import ArgumentsContext 16from knack.commands import CLICommandsLoader, CommandGroup 17 18from tests.util import DummyCLI, redirect_io, assert_in_multi_line 19 20 21def example_handler(arg1, arg2=None, arg3=None): 22 """ Short summary here. Long summary here. Still long summary. """ 23 pass 24 25 26def example_arg_handler(arg1, opt1, arg2=None, opt2=None, arg3=None, 27 opt3=None, arg4=None, opt4=None, arg5=None, opt5=None): 28 pass 29 30 31class TestCommandExperimental(unittest.TestCase): 32 33 def setUp(self): 34 35 from knack.help_files import helps 36 37 class ExperimentalTestCommandLoader(CLICommandsLoader): 38 def load_command_table(self, args): 39 super(ExperimentalTestCommandLoader, self).load_command_table(args) 40 with CommandGroup(self, '', '{}#{{}}'.format(__name__)) as g: 41 g.command('cmd1', 'example_handler', is_experimental=True) 42 43 with CommandGroup(self, 'grp1', '{}#{{}}'.format(__name__), is_experimental=True) as g: 44 g.command('cmd1', 'example_handler') 45 46 return self.command_table 47 48 def load_arguments(self, command): 49 with ArgumentsContext(self, '') as c: 50 c.argument('arg1', options_list=['--arg', '-a'], required=False, type=int, choices=[1, 2, 3]) 51 c.argument('arg2', options_list=['-b'], required=True, choices=['a', 'b', 'c']) 52 53 super(ExperimentalTestCommandLoader, self).load_arguments(command) 54 55 helps['grp1'] = """ 56 type: group 57 short-summary: A group. 58""" 59 self.cli_ctx = DummyCLI(commands_loader_cls=ExperimentalTestCommandLoader) 60 61 @redirect_io 62 def test_experimental_command_implicitly_execute(self): 63 """ Ensure general warning displayed when running command from an experimental parent group. """ 64 self.cli_ctx.invoke('grp1 cmd1 -b b'.split()) 65 actual = self.io.getvalue() 66 expected = "Command group 'grp1' is experimental and under development." 67 self.assertIn(expected, actual) 68 69 @redirect_io 70 def test_experimental_command_group_help(self): 71 """ Ensure experimental commands appear correctly in group help view. """ 72 with self.assertRaises(SystemExit): 73 self.cli_ctx.invoke('-h'.split()) 74 actual = self.io.getvalue() 75 expected = u""" 76Group 77 {} 78 79Subgroups: 80 grp1 [Experimental] : A group. 81 82Commands: 83 cmd1 [Experimental] : Short summary here. 84 85""".format(self.cli_ctx.name) 86 assert_in_multi_line(expected, actual) 87 88 @redirect_io 89 def test_experimental_command_plain_execute(self): 90 """ Ensure general warning displayed when running experimental command. """ 91 self.cli_ctx.invoke('cmd1 -b b'.split()) 92 actual = self.io.getvalue() 93 expected = "This command is experimental and under development." 94 self.assertIn(expected, actual) 95 96 97class TestCommandGroupExperimental(unittest.TestCase): 98 99 def setUp(self): 100 101 from knack.help_files import helps 102 103 class ExperimentalTestCommandLoader(CLICommandsLoader): 104 def load_command_table(self, args): 105 super(ExperimentalTestCommandLoader, self).load_command_table(args) 106 107 with CommandGroup(self, 'group1', '{}#{{}}'.format(__name__), is_experimental=True) as g: 108 g.command('cmd1', 'example_handler') 109 110 return self.command_table 111 112 def load_arguments(self, command): 113 with ArgumentsContext(self, '') as c: 114 c.argument('arg1', options_list=['--arg', '-a'], required=False, type=int, choices=[1, 2, 3]) 115 c.argument('arg2', options_list=['-b'], required=True, choices=['a', 'b', 'c']) 116 117 super(ExperimentalTestCommandLoader, self).load_arguments(command) 118 119 helps['group1'] = """ 120 type: group 121 short-summary: A group. 122""" 123 self.cli_ctx = DummyCLI(commands_loader_cls=ExperimentalTestCommandLoader) 124 125 @redirect_io 126 def test_experimental_command_group_help_plain(self): 127 """ Ensure help warnings appear for experimental command group help. """ 128 with self.assertRaises(SystemExit): 129 self.cli_ctx.invoke('group1 -h'.split()) 130 actual = self.io.getvalue() 131 expected = """ 132Group 133 cli group1 : A group. 134 This command group is experimental and under development. 135Commands: 136 cmd1 : Short summary here. 137 138""".format(self.cli_ctx.name) 139 assert_in_multi_line(expected, actual) 140 141 @redirect_io 142 def test_experimental_command_implicitly(self): 143 """ Ensure help warning displayed for command in experimental because of a experimental parent group. """ 144 with self.assertRaises(SystemExit): 145 self.cli_ctx.invoke('group1 cmd1 -h'.split()) 146 actual = self.io.getvalue() 147 expected = """ 148Command 149 {} group1 cmd1 : Short summary here. 150 Long summary here. Still long summary. 151 Command group 'group1' is experimental and under development. 152""".format(self.cli_ctx.name) 153 assert_in_multi_line(expected, actual) 154 155 156class TestArgumentExperimental(unittest.TestCase): 157 158 def setUp(self): 159 from knack.help_files import helps 160 161 class LoggerAction(argparse.Action): 162 163 def __call__(self, parser, namespace, values, option_string=None): 164 print("Side-effect from some original action!", file=sys.stderr) 165 166 class ExperimentalTestCommandLoader(CLICommandsLoader): 167 def load_command_table(self, args): 168 super(ExperimentalTestCommandLoader, self).load_command_table(args) 169 with CommandGroup(self, '', '{}#{{}}'.format(__name__)) as g: 170 g.command('arg-test', 'example_arg_handler') 171 return self.command_table 172 173 def load_arguments(self, command): 174 with ArgumentsContext(self, 'arg-test') as c: 175 c.argument('arg1', help='Arg1', is_experimental=True, action=LoggerAction) 176 177 super(ExperimentalTestCommandLoader, self).load_arguments(command) 178 179 helps['grp1'] = """ 180 type: group 181 short-summary: A group. 182""" 183 self.cli_ctx = DummyCLI(commands_loader_cls=ExperimentalTestCommandLoader) 184 185 @redirect_io 186 def test_experimental_arguments_command_help(self): 187 """ Ensure experimental arguments appear correctly in command help view. """ 188 with self.assertRaises(SystemExit): 189 self.cli_ctx.invoke('arg-test -h'.split()) 190 actual = self.io.getvalue() 191 expected = """ 192Arguments 193 --arg1 [Experimental] [Required] : Arg1. 194 Argument '--arg1' is experimental and under development. 195""".format(self.cli_ctx.name) 196 assert_in_multi_line(expected, actual) 197 198 @redirect_io 199 def test_experimental_arguments_execute(self): 200 """ Ensure deprecated arguments can be used. """ 201 self.cli_ctx.invoke('arg-test --arg1 foo --opt1 bar'.split()) 202 actual = self.io.getvalue() 203 experimental_expected = "Argument '--arg1' is experimental and under development." 204 self.assertIn(experimental_expected, actual) 205 206 action_expected = "Side-effect from some original action!" 207 self.assertIn(action_expected, actual) 208 209 210if __name__ == '__main__': 211 unittest.main() 212