def test_getch_disabled(self): t = TerminalHandler(stdin=FakeInput('a\nb\ncd\ne\n'), keep_input_clean=False, getch_enabled=False) self.assertEqual(t.getch(), 'a') self.assertEqual(t.getch(), 'b') self.assertEqual(t.getch(), 'c') self.assertEqual(t.getch(), 'e') self.assertRaises(EOFError, t.getch)
def test_getch_not_keep_input_clean(self): fin = FakeBytesInput(b'abcde') t1 = TerminalHandler(stdin=fin, keep_input_clean=False) self.assertEqual(t1.getch(), 'a') self.assertEqual(t1.getch(), 'b') self.assertEqual(t1.getch(), 'c') self.assertEqual(t1.getch(), 'd') self.assertEqual(t1.getch(), 'e') self.assertEqual(t1.getch(), '')
def main(stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, keep_input_clean=True, timing=True): """ Main function """ base_setting = Setting(stdin=stdin, stdout=stdout, stderr=stderr).parse_args(sys.argv) # for terminal restoration handler = TerminalHandler(stdin=stdin, stdout=stdout, stderr=stderr, keep_input_clean=keep_input_clean, getch_enabled=base_setting.getch_enabled) signal.signal(signal.SIGTERM, handler.restore_terminal) try: setting = base_setting.resolve_encoding(handler).lookup_config().load_config() executor = CommandExecutor( SystemLogger(setting.encoding), setting.encoding, stdin, stdout, stderr, setting.pid_dir ) t = Terminal( setting.root_menu, get_hostname(), get_username(), executor, handler=handler, _input=setting.stdin, _output=setting.stdout, encoding=setting.encoding, lang=setting.lang, width=setting.width, timing=timing ) t.loop() except (KeyboardInterrupt, EOFError): pass except EasyMenuError as e: base_setting.stdout.write('%s: %s\n' % (e.__class__.__name__, e)) return 2 except IOError as e: # maybe killed by outside base_setting.stdout.write('\n%s: %s\n' % (e.__class__.__name__, e)) return 3 except OSError as e: # e.g. working directory does not exist base_setting.stdout.write('%s: %s\n' % (e.__class__.__name__, e)) return 4 finally: # assume to restore original terminal settings handler.restore_terminal(None, None) return 0
def test_wait_input_menu(self): self.maxDiff = None _in = FakeInput('a\n9\n0\n') expected = '\n'.join([ 'Host: host User: user', '================================================================================', ' ', '--------------------------------------------------------------------------------', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-0): ', ]) * 3 with self.withAssertOutput(expected, '') as (out, err): t = Terminal(Menu('', [], Meta()), 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=err), handler=TerminalHandler(stdin=_in, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop()
def test_resolve_encoding(self): from mog_commons.terminal import TerminalHandler handler = TerminalHandler(encoding='sjis') self.assertEqual(Setting().resolve_encoding(handler).encoding, 'sjis') self.assertEqual( Setting(encoding='utf-8').resolve_encoding(handler).encoding, 'utf-8')
def test_loop(self): self.maxDiff = None root_menu = Menu('Main menu', [ Command('Menu a', [CommandLine('echo executing a', Meta())]), Command('Menu b', [CommandLine('echo executing b && exit 130', Meta())]), Menu('Sub Menu 1', [ Command('Menu 1', [CommandLine('echo executing 1', Meta())]), Command('Menu 2', [CommandLine('echo executing 2', Meta())]), Command('Menu 3', [CommandLine('echo executing 3', Meta())]), Command('Menu 4', [CommandLine('echo executing 4', Meta())]), Command('Menu 5', [CommandLine('echo executing 5', Meta())]), Command('Menu 6', [CommandLine('echo executing 6', Meta())]), Command('Menu 7', [CommandLine('echo executing 7', Meta())]), Command('Menu 8', [CommandLine('echo executing 8', Meta())]), Command('Menu 9', [CommandLine('echo executing 9', Meta())]), Command('Menu 10', [CommandLine('echo executing 10', Meta())]), ], Meta()) ], Meta()) _in = FakeInput(''.join([ '1n', '1N', '1\n', '1yx', '2Yx', '3n', '1yx', 'p', '9yx', '0', '-0' ])) # We use a temporary file due to capture the output of subprocess#call. path = os.path.join('tests', 'resources', 'expect', 'terminal_test_loop.txt') with self.withAssertOutputFile(path) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() self.assertEqual(t.executor.logger.buffer, [ (6, '[INFO] Command started: echo executing a'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo executing b && exit 130'), (6, '[INFO] Command ended with return code: 130'), (6, '[INFO] Command started: echo executing 10'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo executing 9'), (6, '[INFO] Command ended with return code: 0'), ])
def test_resolve_encoding(self): import io import codecs if six.PY2: out = codecs.getwriter('sjis') out.encoding = 'sjis' else: out = io.TextIOWrapper(six.StringIO(), 'sjis') self.assertEqual(TerminalHandler._detect_encoding(out), 'sjis')
def test_wait_input_char(self): _in = FakeInput('xyz\x03\n\x04') t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=TerminalHandler(stdin=_in, keep_input_clean=False), _input=_in) self.assertEqual(t.wait_input_char(), 'x') self.assertEqual(t.wait_input_char(), 'y') self.assertEqual(t.wait_input_char(), 'z') self.assertRaises(KeyboardInterrupt, t.wait_input_char) self.assertEqual(t.wait_input_char(), '\n') self.assertRaises(KeyboardInterrupt, t.wait_input_char)
def test_print_source(self): self.maxDiff = None root_meta = Meta('/path/to/work', {'ENV1': 'VAL1', 'ENV2': 'VAL2'}) sub_meta = Meta('/tmp2', {'ENV1': 'VAL1', 'ENV2': 'VAL2'}) special_meta = Meta('/path/to/work2', { 'ENV1': 'VAL9', 'ENV2': 'VAL2', 'ENV3': 'VAL3' }) root_menu = Menu('Main menu', [ Command('label 1', [CommandLine('command 1', root_meta)]), Command('label 2', [CommandLine('command 2', root_meta)]), Command('label 3', [ CommandLine('command 3', special_meta), CommandLine('command 4', root_meta) ]), Menu('sub menu', [Command('label s1', [CommandLine('command 5', sub_meta)])], sub_meta), Command('label 9', [CommandLine('command 9', root_meta)]), ], root_meta) _in = FakeInput('s\nx\n0\n') path = os.path.join('tests', 'resources', 'expect', 'terminal_test_print_source.txt') with self.withAssertOutputFile(path, {'': ''}) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop()
def test_print_source_ja(self): self.maxDiff = None root_meta = Meta('/path/to/work', {'ENV1': '値1', 'ENV2': '値2'}) sub_meta = Meta('/tmp2', {'ENV1': '値1', 'ENV2': '値2'}) special_meta = Meta('/path/to/work2', { 'ENV1': '値9', 'ENV2': '値2', 'ENV3': '値3' }) root_menu = Menu('メイン メニュー', [ Command('メニュー 1', [CommandLine('コマンド 1', root_meta)]), Command('メニュー 2', [CommandLine('コマンド 2', root_meta)]), Command('メニュー 3', [ CommandLine('コマンド 3', special_meta), CommandLine('command 4', root_meta) ]), Menu('サブ メニュー', [Command('メニュー s1', [CommandLine('コマンド 5', sub_meta)])], sub_meta), Command('メニュー 9', [CommandLine('コマンド 9', root_meta)]), ], root_meta) _in = FakeInput('s\nx\n0\n') path = os.path.join('tests', 'resources', 'expect', 'terminal_test_print_source_ja.txt') with self.withAssertOutputFile(path, {'': ''}) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='ja_JP', width=80, timing=False) t.loop()
def test_getch_key_repeat_disabled(self): fin = FakeBytesInput(b'abcde') def append_char(ch): fin.write(ch) fin.seek(-len(ch), 1) t1 = TerminalHandler(stdin=fin, getch_repeat_threshold=0) self.assertEqual(t1.getch(), 'a') append_char(b'x') self.assertEqual(t1.getch(), 'x') append_char(b'x') self.assertEqual(t1.getch(), 'x') append_char(b'x') self.assertEqual(t1.getch(), 'x') append_char(b'y') self.assertEqual(t1.getch(), 'y') append_char(b'y') self.assertEqual(t1.getch(), 'y') time.sleep(1) append_char(b'y') self.assertEqual(t1.getch(), 'y')
def test_loop_sjis(self): self.maxDiff = None root_menu = Menu( 'メインメニュー', [Command('メニュー 1', [CommandLine("echo 'あいうえお'", Meta())])], Meta()) _in = FakeInput(''.join(['1yx', '0'])) # We use a temporary file due to capture the output of subprocess#call. path = os.path.join('tests', 'resources', 'expect', 'terminal_test_loop_sjis.txt') with self.withAssertOutputFile(path, expect_file_encoding='sjis', output_encoding='sjis') as out: t = Terminal(root_menu, 'ホスト', 'ユーザ', self.get_exec(encoding='sjis', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='sjis', lang='ja_JP', width=80, timing=False) t.loop() # out.seek(0) # print(out.read()) self.assertEqual(t.executor.logger.buffer, [ (6, "[INFO] Command started: echo 'あいうえお'"), (6, "[INFO] Command ended with return code: 0"), ])
def test_loop_multiple_commands(self): self.maxDiff = None root_menu = Menu('Main Menu', [ Menu('Sub Menu 1', [ Command('Menu 1', [ CommandLine('echo 1', Meta()), CommandLine('echo 2', Meta()), ]) ], Meta()), Menu('Sub Menu 2', [ Menu('Sub Menu 3', [ Command('Menu 3', [CommandLine('echo 3', Meta())]), Command('Menu 4', [CommandLine('echo 4', Meta())]), ], Meta()), Command('Menu 5', [CommandLine('echo 5', Meta())]) ], Meta()), Command('Menu 6', [ CommandLine('echo 6', Meta()), CommandLine('echo 7', Meta()), CommandLine('false', Meta()), CommandLine('echo 8', Meta()), ]) ], Meta()) _in = FakeInput(''.join( ['1', '.1yx', '0', '21.1yx', '0.0', '3yx', '0'])) # We use a temporary file due to capture the output of subprocess#call. with self.withAssertOutputFile( 'tests/resources/expect/terminal_test_loop_multiple_commands.txt' ) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() self.assertEqual(t.executor.logger.buffer, [ (6, '[INFO] Command started: echo 1'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 2'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 3'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 6'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 7'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: false'), (6, '[INFO] Command ended with return code: 1'), ])
class TestTerminal(TestCase): handler = TerminalHandler(keep_input_clean=False) def get_exec(self, encoding='utf-8', stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, pid_dir='/tmp'): return CommandExecutor(MockLogger(), encoding, stdin, stdout, stderr, pid_dir) def test_init(self): t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler) self.assertEqual(t.root_menu, {'': []}) self.assertEqual(t.host, 'host') self.assertEqual(t.user, 'user') def test_init_error(self): self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, 0) self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, 39) self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, -1) self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, page_size=0) self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, page_size=-1) self.assertRaises(SettingError, Terminal, {'': []}, 'host', 'user', self.get_exec(), self.handler, page_size=10) def test_print_error(self): t = Terminal({'': []}, 'hose', 'user', self.get_exec(), handler=self.handler, encoding='ascii', lang='ja') with self.withAssertOutput('', '') as (out, err): self.assertRaisesRegexp( EncodingError, '^Failed to print menu: lang=ja, encoding=ascii$', lambda: t._print('\n'.join(t._get_header('Header')))) def test_get_breadcrumb(self): t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='C', width=80) self.assertEqual( t._get_breadcrumb(['a' * 50, 'b' * 50]), '~aaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ) self.assertEqual( t._get_breadcrumb(['a' * 75]), 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) self.assertEqual( t._get_breadcrumb(['a' * 76]), '~aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' ) self.assertEqual( t._get_breadcrumb([''] * 26), ' > > > > > > > > > > > > > > > > > > > > > > > > > ' ) self.assertEqual( t._get_breadcrumb([''] * 27), '~ > > > > > > > > > > > > > > > > > > > > > > > > > ' ) self.assertEqual(t._get_breadcrumb(['a' + 'あ' * 37]), 'aあああああああああああああああああああああああああああああああああああああ') self.assertEqual(t._get_breadcrumb(['あ' * 38]), '~あああああああああああああああああああああああああああああああああああああ') self.assertEqual(t._get_breadcrumb(['a' + 'あ' * 38]), '~あああああああああああああああああああああああああああああああああああああ') self.assertEqual(t._get_breadcrumb(['あ' * 38 + 'a']), '~あああああああああああああああああああああああああああああああああああああa') def test_get_page(self): self.maxDiff = None t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='C', width=80) self.assertEqual( t.get_page(['title'], [], 0, 1), '\n'.join([ 'Host: host User: user', '================================================================================', ' title', '--------------------------------------------------------------------------------', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-0): ' ])) self.assertEqual( t.get_page(['Main Menu', 'title'], [ Command('menu a', [CommandLine('command a', Meta())]), Command('menu b', [CommandLine('command b', Meta())]), Command('menu c', [CommandLine('command c', Meta())]), ], 0, 1), '\n'.join([ 'Host: host User: user', '================================================================================', ' Main Menu > title', '--------------------------------------------------------------------------------', ' [1] | menu a', ' [2] | menu b', ' [3] | menu c', '------+-------------------------------------------------------------------------', ' [0] | Return to Main Menu', '================================================================================', 'Press menu number (0-3): ' ])) self.assertEqual( t.get_page(['title'], [ Command('menu a', [CommandLine('command a', Meta())]), Command('menu b', [CommandLine('command b', Meta())]), Command('menu c', [CommandLine('command c', Meta())]), Command('menu d', [CommandLine('command d', Meta())]), Command('menu e', [CommandLine('command e', Meta())]), Command('menu f', [CommandLine('command f', Meta())]), Command('menu g', [CommandLine('command g', Meta())]), Command('menu h', [CommandLine('command h', Meta())]), Command('menu i', [CommandLine('command i', Meta())]), ], 0, 100), '\n'.join([ 'Host: host User: user', '================================================================================', ' title', '--------------------------------------------------------------------------------', ' Page 1 / 100 [N] =>', '--------------------------------------------------------------------------------', ' [1] | menu a', ' [2] | menu b', ' [3] | menu c', ' [4] | menu d', ' [5] | menu e', ' [6] | menu f', ' [7] | menu g', ' [8] | menu h', ' [9] | menu i', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-9): ' ])) self.assertEqual( t.get_page(['title'], [ Command('menu a', [CommandLine('command a', Meta())]), Command('menu b', [CommandLine('command b', Meta())]), Command('menu c', [CommandLine('command c', Meta())]), Command('menu d', [CommandLine('command d', Meta())]), Command('menu e', [CommandLine('command e', Meta())]), Command('menu f', [CommandLine('command f', Meta())]), Command('menu g', [CommandLine('command g', Meta())]), Command('menu h', [CommandLine('command h', Meta())]), Command('menu i', [CommandLine('command i', Meta())]), ], 8, 100), '\n'.join([ 'Host: host User: user', '================================================================================', ' title', '--------------------------------------------------------------------------------', '<= [P] Page 9 / 100 [N] =>', '--------------------------------------------------------------------------------', ' [1] | menu a', ' [2] | menu b', ' [3] | menu c', ' [4] | menu d', ' [5] | menu e', ' [6] | menu f', ' [7] | menu g', ' [8] | menu h', ' [9] | menu i', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-9): ' ])) self.assertEqual( t.get_page(['title'], [ Command('menu a', [CommandLine('command a', Meta())]), ], 99, 100), '\n'.join([ 'Host: host User: user', '================================================================================', ' title', '--------------------------------------------------------------------------------', '<= [P] Page 100 / 100 ', '--------------------------------------------------------------------------------', ' [1] | menu a', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-1): ' ])) # sub menu self.assertEqual( t.get_page(['Main Menu', 'title'], [ Menu('menu a', [Command('menu b', [CommandLine('command b', Meta())])], Meta()), Menu('menu c', [ Command('menu c', [CommandLine('command c', Meta())]), Command('menu d', [CommandLine('command d', Meta())]), ], Meta()), ], 0, 1), '\n'.join([ 'Host: host User: user', '================================================================================', ' Main Menu > title', '--------------------------------------------------------------------------------', ' [1] | Go to menu a', ' [2] | Go to menu c', '------+-------------------------------------------------------------------------', ' [0] | Return to Main Menu', '================================================================================', 'Press menu number (0-2): ' ])) # multiple command lines self.assertEqual( t.get_page(['Main Menu', 'title'], [ Command('menu a', [CommandLine('command a', Meta())]), Command('menu b', [ CommandLine('command b', Meta()), CommandLine('command b', Meta()), ]), Menu('menu c', [ Command('menu d', [ CommandLine('command d', Meta()), CommandLine('command d', Meta()), ]) ], Meta()), ], 0, 1), '\n'.join([ 'Host: host User: user', '================================================================================', ' Main Menu > title', '--------------------------------------------------------------------------------', ' [1] | menu a', ' [2] | menu b', ' [3] | Go to menu c', '------+-------------------------------------------------------------------------', ' [0] | Return to Main Menu', '================================================================================', 'Press menu number (0-3): ' ])) def test_get_page_ja(self): self.maxDiff = None t = Terminal({'': []}, 'ホスト', 'ユーザ', self.get_exec(), handler=self.handler, encoding='utf-8', lang='ja_JP', width=80) self.assertEqual( t.get_page(['タイトル'], [], 0, 1), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' タイトル', '--------------------------------------------------------------------------------', '------+-------------------------------------------------------------------------', ' [0] | 終了', '================================================================================', '番号を入力してください (0-0): ' ])) self.assertEqual( t.get_page(['メインメニュー', 'タイトル'], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), Command('メニュー b', [CommandLine('コマンド b', Meta())]), Command('メニュー c', [CommandLine('コマンド c', Meta())]), ], 0, 1), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' メインメニュー > タイトル', '--------------------------------------------------------------------------------', ' [1] | メニュー a', ' [2] | メニュー b', ' [3] | メニュー c', '------+-------------------------------------------------------------------------', ' [0] | メインメニュー に戻る', '================================================================================', '番号を入力してください (0-3): ' ])) self.assertEqual( t.get_page([ 'メインメニュー', 'タイトル1', 'タイトル2', 'タイトル3', 'タイトル4', 'タイトル5', 'タイトル6', 'タイトル7', 'タイトル8', ], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), Command('メニュー b', [CommandLine('コマンド b', Meta())]), Command('メニュー c', [CommandLine('コマンド c', Meta())]), ], 0, 1), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' ~ル2 > タイトル3 > タイトル4 > タイトル5 > タイトル6 > タイトル7 > タイトル8', '--------------------------------------------------------------------------------', ' [1] | メニュー a', ' [2] | メニュー b', ' [3] | メニュー c', '------+-------------------------------------------------------------------------', ' [0] | タイトル7 に戻る', '================================================================================', '番号を入力してください (0-3): ' ])) self.assertEqual( t.get_page(['タイトル'], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), Command('メニュー b', [CommandLine('コマンド b', Meta())]), Command('メニュー c', [CommandLine('コマンド c', Meta())]), Command('メニュー d', [CommandLine('コマンド d', Meta())]), Command('メニュー e', [CommandLine('コマンド e', Meta())]), Command('メニュー f', [CommandLine('コマンド f', Meta())]), Command('メニュー g', [CommandLine('コマンド g', Meta())]), Command('メニュー h', [CommandLine('コマンド h', Meta())]), Command('メニュー i', [CommandLine('コマンド i', Meta())]), ], 0, 100), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' タイトル', '--------------------------------------------------------------------------------', ' Page 1 / 100 [N] =>', '--------------------------------------------------------------------------------', ' [1] | メニュー a', ' [2] | メニュー b', ' [3] | メニュー c', ' [4] | メニュー d', ' [5] | メニュー e', ' [6] | メニュー f', ' [7] | メニュー g', ' [8] | メニュー h', ' [9] | メニュー i', '------+-------------------------------------------------------------------------', ' [0] | 終了', '================================================================================', '番号を入力してください (0-9): ' ])) self.assertEqual( t.get_page(['タイトル'], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), Command('メニュー b', [CommandLine('コマンド b', Meta())]), Command('メニュー c', [CommandLine('コマンド c', Meta())]), Command('メニュー d', [CommandLine('コマンド d', Meta())]), Command('メニュー e', [CommandLine('コマンド e', Meta())]), Command('メニュー f', [CommandLine('コマンド f', Meta())]), Command('メニュー g', [CommandLine('コマンド g', Meta())]), Command('メニュー h', [CommandLine('コマンド h', Meta())]), Command('メニュー i', [CommandLine('コマンド i', Meta())]), ], 8, 100), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' タイトル', '--------------------------------------------------------------------------------', '<= [P] Page 9 / 100 [N] =>', '--------------------------------------------------------------------------------', ' [1] | メニュー a', ' [2] | メニュー b', ' [3] | メニュー c', ' [4] | メニュー d', ' [5] | メニュー e', ' [6] | メニュー f', ' [7] | メニュー g', ' [8] | メニュー h', ' [9] | メニュー i', '------+-------------------------------------------------------------------------', ' [0] | 終了', '================================================================================', '番号を入力してください (0-9): ' ])) self.assertEqual( t.get_page(['タイトル'], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), ], 99, 100), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' タイトル', '--------------------------------------------------------------------------------', '<= [P] Page 100 / 100 ', '--------------------------------------------------------------------------------', ' [1] | メニュー a', '------+-------------------------------------------------------------------------', ' [0] | 終了', '================================================================================', '番号を入力してください (0-1): ' ])) # sub menu self.assertEqual( t.get_page(['メインメニュー', 'タイトル'], [ Menu('メニュー a', [Command('メニュー b', [CommandLine('コマンド b', Meta())])], Meta()), Menu('メニュー c', [ Command('メニュー c', [CommandLine('コマンド c', Meta())]), Command('メニュー d', [CommandLine('コマンド d', Meta())]), ], Meta()), ], 0, 1), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' メインメニュー > タイトル', '--------------------------------------------------------------------------------', ' [1] | メニュー a へ', ' [2] | メニュー c へ', '------+-------------------------------------------------------------------------', ' [0] | メインメニュー に戻る', '================================================================================', '番号を入力してください (0-2): ' ])) # multiple command lines self.assertEqual( t.get_page(['メインメニュー', 'タイトル'], [ Command('メニュー a', [CommandLine('コマンド a', Meta())]), Command('メニュー b', [ CommandLine('コマンド b', Meta()), CommandLine('コマンド b', Meta()), ]), Menu('メニュー c', [ Command('メニュー d', [ CommandLine('コマンド d', Meta()), CommandLine('コマンド d', Meta()), ]) ], Meta()), ], 0, 1), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' メインメニュー > タイトル', '--------------------------------------------------------------------------------', ' [1] | メニュー a', ' [2] | メニュー b', ' [3] | メニュー c へ', '------+-------------------------------------------------------------------------', ' [0] | メインメニュー に戻る', '================================================================================', '番号を入力してください (0-3): ' ])) def test_get_confirm(self): self.maxDiff = None t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='C', width=80) self.assertEqual( t.get_confirm('description'), '\n'.join([ 'Host: host User: user', '================================================================================', ' Confirmation', '--------------------------------------------------------------------------------', ' Would execute: description', '================================================================================', 'Do you really want to execute? (y/n) [n]: ' ])) def test_get_confirm_ja(self): self.maxDiff = None t = Terminal({'': []}, 'ホスト', 'ユーザ', self.get_exec(), handler=self.handler, encoding='utf-8', lang='ja_JP', width=80) self.assertEqual( t.get_confirm('メニュー 1'), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' 実行確認', '--------------------------------------------------------------------------------', ' メニュー 1 を行います。', '================================================================================', 'よろしいですか? (y/n) [n]: ' ])) def test_get_before_execute(self): self.maxDiff = None t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='C', width=80) self.assertEqual( t.get_before_execute('description'), '\n'.join([ 'Host: host User: user', '================================================================================', ' Executing: description', '--------------------------------------------------------------------------------', '' ])) def test_get_before_execute_ja(self): self.maxDiff = None t = Terminal({'': []}, 'ホスト', 'ユーザ', self.get_exec(), handler=self.handler, encoding='utf-8', lang='ja_JP', width=80) self.assertEqual( t.get_before_execute('メニュー 1'), '\n'.join([ 'ホスト名: ホスト 実行ユーザ: ユーザ', '================================================================================', ' 実行: メニュー 1', '--------------------------------------------------------------------------------', '' ])) def test_get_after_execute(self): self.maxDiff = None t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='C', width=80) self.assertEqual( t.get_after_execute('description', 123, datetime(2015, 12, 3, 4, 56, 7, 890000), datetime(2015, 12, 4, 5, 6, 7, 890000)), '\n'.join([ '--------------------------------------------------------------------------------', 'Finished : description', 'Running time: 1d 0h 10m 0s (2015-12-03 04:56:07 -> 2015-12-04 05:06:07)', 'Return code : 123', '================================================================================', 'Press any key to continue...' ])) def test_get_after_execute_ja(self): self.maxDiff = None t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=self.handler, encoding='utf-8', lang='ja_JP', width=80) self.assertEqual( t.get_after_execute('メニュー 1', 123, datetime(2015, 12, 3, 4, 56, 7, 890000), datetime(2015, 12, 4, 5, 6, 7, 890000)), '\n'.join([ '--------------------------------------------------------------------------------', '実行完了 : メニュー 1', 'Running time: 1d 0h 10m 0s (2015-12-03 04:56:07 -> 2015-12-04 05:06:07)', 'Return code : 123', '================================================================================', '何かキーを押すとメニューに戻ります...' ])) def test_format_timedelta(self): self.assertEqual(Terminal._format_timedelta(timedelta(-1, 1)), '') self.assertEqual(Terminal._format_timedelta(timedelta(0, 0)), '0ms') self.assertEqual(Terminal._format_timedelta(timedelta(0, 0, 1)), '0ms') self.assertEqual(Terminal._format_timedelta(timedelta(0, 0, 999)), '0ms') self.assertEqual(Terminal._format_timedelta(timedelta(0, 0, 1000)), '1ms') self.assertEqual(Terminal._format_timedelta(timedelta(0, 0, 999999)), '999ms') self.assertEqual(Terminal._format_timedelta(timedelta(0, 1, 999)), '1s') self.assertEqual(Terminal._format_timedelta(timedelta(0, 60, 999)), '1m 0s') self.assertEqual(Terminal._format_timedelta(timedelta(0, 3600, 999)), '1h 0m 0s') self.assertEqual(Terminal._format_timedelta(timedelta(0, 3601, 999)), '1h 0m 1s') self.assertEqual(Terminal._format_timedelta(timedelta(0, 86399, 999)), '23h 59m 59s') self.assertEqual(Terminal._format_timedelta(timedelta(1, 0, 0)), '1d 0h 0m 0s') self.assertEqual(Terminal._format_timedelta(timedelta(50, 50000, 0)), '50d 13h 53m 20s') def test_format_datetime(self): self.assertEqual( Terminal._format_datetime(datetime(2015, 12, 3, 4, 56, 7, 890000)), '2015-12-03 04:56:07') @base_unittest.skipUnless(os.name != 'nt', 'requires POSIX compatible') def test_wait_input_char(self): _in = FakeInput('xyz\x03\n\x04') t = Terminal({'': []}, 'host', 'user', self.get_exec(), handler=TerminalHandler(stdin=_in, keep_input_clean=False), _input=_in) self.assertEqual(t.wait_input_char(), 'x') self.assertEqual(t.wait_input_char(), 'y') self.assertEqual(t.wait_input_char(), 'z') self.assertRaises(KeyboardInterrupt, t.wait_input_char) self.assertEqual(t.wait_input_char(), '\n') self.assertRaises(KeyboardInterrupt, t.wait_input_char) def test_wait_input_menu(self): self.maxDiff = None _in = FakeInput('a\n9\n0\n') expected = '\n'.join([ 'Host: host User: user', '================================================================================', ' ', '--------------------------------------------------------------------------------', '------+-------------------------------------------------------------------------', ' [0] | Quit', '================================================================================', 'Press menu number (0-0): ', ]) * 3 with self.withAssertOutput(expected, '') as (out, err): t = Terminal(Menu('', [], Meta()), 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=err), handler=TerminalHandler(stdin=_in, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() def test_print_source(self): self.maxDiff = None root_meta = Meta('/path/to/work', {'ENV1': 'VAL1', 'ENV2': 'VAL2'}) sub_meta = Meta('/tmp2', {'ENV1': 'VAL1', 'ENV2': 'VAL2'}) special_meta = Meta('/path/to/work2', { 'ENV1': 'VAL9', 'ENV2': 'VAL2', 'ENV3': 'VAL3' }) root_menu = Menu('Main menu', [ Command('label 1', [CommandLine('command 1', root_meta)]), Command('label 2', [CommandLine('command 2', root_meta)]), Command('label 3', [ CommandLine('command 3', special_meta), CommandLine('command 4', root_meta) ]), Menu('sub menu', [Command('label s1', [CommandLine('command 5', sub_meta)])], sub_meta), Command('label 9', [CommandLine('command 9', root_meta)]), ], root_meta) _in = FakeInput('s\nx\n0\n') path = os.path.join('tests', 'resources', 'expect', 'terminal_test_print_source.txt') with self.withAssertOutputFile(path, {'': ''}) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() def test_print_source_ja(self): self.maxDiff = None root_meta = Meta('/path/to/work', {'ENV1': '値1', 'ENV2': '値2'}) sub_meta = Meta('/tmp2', {'ENV1': '値1', 'ENV2': '値2'}) special_meta = Meta('/path/to/work2', { 'ENV1': '値9', 'ENV2': '値2', 'ENV3': '値3' }) root_menu = Menu('メイン メニュー', [ Command('メニュー 1', [CommandLine('コマンド 1', root_meta)]), Command('メニュー 2', [CommandLine('コマンド 2', root_meta)]), Command('メニュー 3', [ CommandLine('コマンド 3', special_meta), CommandLine('command 4', root_meta) ]), Menu('サブ メニュー', [Command('メニュー s1', [CommandLine('コマンド 5', sub_meta)])], sub_meta), Command('メニュー 9', [CommandLine('コマンド 9', root_meta)]), ], root_meta) _in = FakeInput('s\nx\n0\n') path = os.path.join('tests', 'resources', 'expect', 'terminal_test_print_source_ja.txt') with self.withAssertOutputFile(path, {'': ''}) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False, getch_enabled=False), _input=_in, _output=out, encoding='utf-8', lang='ja_JP', width=80, timing=False) t.loop() @base_unittest.skipUnless(os.name != 'nt', 'requires POSIX compatible') def test_loop(self): self.maxDiff = None root_menu = Menu('Main menu', [ Command('Menu a', [CommandLine('echo executing a', Meta())]), Command('Menu b', [CommandLine('echo executing b && exit 130', Meta())]), Menu('Sub Menu 1', [ Command('Menu 1', [CommandLine('echo executing 1', Meta())]), Command('Menu 2', [CommandLine('echo executing 2', Meta())]), Command('Menu 3', [CommandLine('echo executing 3', Meta())]), Command('Menu 4', [CommandLine('echo executing 4', Meta())]), Command('Menu 5', [CommandLine('echo executing 5', Meta())]), Command('Menu 6', [CommandLine('echo executing 6', Meta())]), Command('Menu 7', [CommandLine('echo executing 7', Meta())]), Command('Menu 8', [CommandLine('echo executing 8', Meta())]), Command('Menu 9', [CommandLine('echo executing 9', Meta())]), Command('Menu 10', [CommandLine('echo executing 10', Meta())]), ], Meta()) ], Meta()) _in = FakeInput(''.join([ '1n', '1N', '1\n', '1yx', '2Yx', '3n', '1yx', 'p', '9yx', '0', '-0' ])) # We use a temporary file due to capture the output of subprocess#call. path = os.path.join('tests', 'resources', 'expect', 'terminal_test_loop.txt') with self.withAssertOutputFile(path) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() self.assertEqual(t.executor.logger.buffer, [ (6, '[INFO] Command started: echo executing a'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo executing b && exit 130'), (6, '[INFO] Command ended with return code: 130'), (6, '[INFO] Command started: echo executing 10'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo executing 9'), (6, '[INFO] Command ended with return code: 0'), ]) @base_unittest.skipUnless(os.name != 'nt', 'requires POSIX compatible') def test_loop_sjis(self): self.maxDiff = None root_menu = Menu( 'メインメニュー', [Command('メニュー 1', [CommandLine("echo 'あいうえお'", Meta())])], Meta()) _in = FakeInput(''.join(['1yx', '0'])) # We use a temporary file due to capture the output of subprocess#call. path = os.path.join('tests', 'resources', 'expect', 'terminal_test_loop_sjis.txt') with self.withAssertOutputFile(path, expect_file_encoding='sjis', output_encoding='sjis') as out: t = Terminal(root_menu, 'ホスト', 'ユーザ', self.get_exec(encoding='sjis', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='sjis', lang='ja_JP', width=80, timing=False) t.loop() # out.seek(0) # print(out.read()) self.assertEqual(t.executor.logger.buffer, [ (6, "[INFO] Command started: echo 'あいうえお'"), (6, "[INFO] Command ended with return code: 0"), ]) @base_unittest.skipUnless(os.name != 'nt', 'requires POSIX compatible') def test_loop_multiple_commands(self): self.maxDiff = None root_menu = Menu('Main Menu', [ Menu('Sub Menu 1', [ Command('Menu 1', [ CommandLine('echo 1', Meta()), CommandLine('echo 2', Meta()), ]) ], Meta()), Menu('Sub Menu 2', [ Menu('Sub Menu 3', [ Command('Menu 3', [CommandLine('echo 3', Meta())]), Command('Menu 4', [CommandLine('echo 4', Meta())]), ], Meta()), Command('Menu 5', [CommandLine('echo 5', Meta())]) ], Meta()), Command('Menu 6', [ CommandLine('echo 6', Meta()), CommandLine('echo 7', Meta()), CommandLine('false', Meta()), CommandLine('echo 8', Meta()), ]) ], Meta()) _in = FakeInput(''.join( ['1', '.1yx', '0', '21.1yx', '0.0', '3yx', '0'])) # We use a temporary file due to capture the output of subprocess#call. with self.withAssertOutputFile( 'tests/resources/expect/terminal_test_loop_multiple_commands.txt' ) as out: t = Terminal(root_menu, 'host', 'user', self.get_exec(encoding='utf-8', stdout=out, stderr=out), handler=TerminalHandler(stdin=_in, stdout=out, stderr=out, keep_input_clean=False), _input=_in, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.loop() self.assertEqual(t.executor.logger.buffer, [ (6, '[INFO] Command started: echo 1'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 2'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 3'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 6'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: echo 7'), (6, '[INFO] Command ended with return code: 0'), (6, '[INFO] Command started: false'), (6, '[INFO] Command ended with return code: 1'), ]) def test_execute_command_duplicate(self): self.maxDiff = None sleep_cmd = 'python -c "import time;time.sleep(1)"' if os.name == 'nt' else 'sleep 1' _in1 = FakeInput('\n'.join(['y', '\r'])) _in2 = FakeInput('\n'.join(['y', '\r'])) root_menu = Menu( 'Main Menu', [Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))])]) expected_en = '\n'.join([ 'Host: host User: user', '================================================================================', ' Confirmation', '--------------------------------------------------------------------------------', ' Would execute: Menu 1', '================================================================================', 'Do you really want to execute? (y/n) [n]: ' 'Host: host User: user', '================================================================================', ' Duplicate check', '--------------------------------------------------------------------------------', ' Already running: Menu 1', '================================================================================', 'Do you really want to continue? (y/n) [n]: ', ]) with self.withAssertOutput(expected_en, '') as (out, err): t = Terminal(root_menu, 'host', 'user', MockExecutor(0, True), TerminalHandler(stdin=_in1, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in1, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.execute_command( Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))])) expected_ja = '\n'.join([ 'ホスト名: host 実行ユーザ: user', '================================================================================', ' 実行確認', '--------------------------------------------------------------------------------', ' Menu 1 を行います。', '================================================================================', 'よろしいですか? (y/n) [n]: ' 'ホスト名: host 実行ユーザ: user', '================================================================================', ' 多重実行チェック', '--------------------------------------------------------------------------------', ' Menu 1 は既に実行中です。', '================================================================================', '本当によろしいですか? (y/n) [n]: ', ]) with self.withAssertOutput(expected_ja, '') as (out, err): t = Terminal(root_menu, 'host', 'user', MockExecutor(0, True), TerminalHandler(stdin=_in2, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in2, _output=out, encoding='utf-8', lang='ja_JP', width=80, timing=False) t.execute_command( Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))]))
def test_getch(self): self.assertEqual(TerminalHandler(stdin=FakeBytesInput(b'')).getch(), '') self.assertEqual(TerminalHandler(stdin=FakeBytesInput(b'\x03')).getch(), '\x03') self.assertEqual(TerminalHandler(stdin=FakeBytesInput(b'abc')).getch(), 'a') self.assertEqual(TerminalHandler(stdin=FakeBytesInput('あ'.encode('utf-8'))).getch(), '') self.assertEqual(TerminalHandler(stdin=FakeBytesInput('あ'.encode('sjis'))).getch(), '')
def test_getch_from_file(self): with open(os.path.join('tests', 'resources', 'test_terminal_input.txt')) as f: t = TerminalHandler(stdin=f) self.assertEqual(t.getch(), 'a') self.assertRaises(EOFError, t.getch)
def test_init(self): self.assertEqual(TerminalHandler(stdin=six.StringIO(), getch_enabled=False).getch_enabled, False) self.assertEqual(TerminalHandler(stdin=six.StringIO(), getch_enabled=True).getch_enabled, False) self.assertEqual(TerminalHandler(stdin=FakeInput(), getch_enabled=False).getch_enabled, False) self.assertEqual(TerminalHandler(stdin=FakeInput(), getch_enabled=True).getch_enabled, True)
def test_clear(self): with self.withAssertOutput('', '') as (out, err): # assume this should not raise an error TerminalHandler(stdout=out, stderr=err).clear()
def test_execute_command_duplicate(self): self.maxDiff = None sleep_cmd = 'python -c "import time;time.sleep(1)"' if os.name == 'nt' else 'sleep 1' _in1 = FakeInput('\n'.join(['y', '\r'])) _in2 = FakeInput('\n'.join(['y', '\r'])) root_menu = Menu( 'Main Menu', [Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))])]) expected_en = '\n'.join([ 'Host: host User: user', '================================================================================', ' Confirmation', '--------------------------------------------------------------------------------', ' Would execute: Menu 1', '================================================================================', 'Do you really want to execute? (y/n) [n]: ' 'Host: host User: user', '================================================================================', ' Duplicate check', '--------------------------------------------------------------------------------', ' Already running: Menu 1', '================================================================================', 'Do you really want to continue? (y/n) [n]: ', ]) with self.withAssertOutput(expected_en, '') as (out, err): t = Terminal(root_menu, 'host', 'user', MockExecutor(0, True), TerminalHandler(stdin=_in1, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in1, _output=out, encoding='utf-8', lang='en_US', width=80, timing=False) t.execute_command( Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))])) expected_ja = '\n'.join([ 'ホスト名: host 実行ユーザ: user', '================================================================================', ' 実行確認', '--------------------------------------------------------------------------------', ' Menu 1 を行います。', '================================================================================', 'よろしいですか? (y/n) [n]: ' 'ホスト名: host 実行ユーザ: user', '================================================================================', ' 多重実行チェック', '--------------------------------------------------------------------------------', ' Menu 1 は既に実行中です。', '================================================================================', '本当によろしいですか? (y/n) [n]: ', ]) with self.withAssertOutput(expected_ja, '') as (out, err): t = Terminal(root_menu, 'host', 'user', MockExecutor(0, True), TerminalHandler(stdin=_in2, stdout=out, stderr=err, keep_input_clean=False, getch_enabled=False), _input=_in2, _output=out, encoding='utf-8', lang='ja_JP', width=80, timing=False) t.execute_command( Command('Menu 1', [CommandLine(sleep_cmd, Meta(lock=True))]))