%PDF- %PDF-
Direktori : /lib/python3/dist-packages/twisted/conch/test/ |
Current File : //lib/python3/dist-packages/twisted/conch/test/test_helper.py |
# -*- test-case-name: twisted.conch.test.test_helper -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from __future__ import annotations import re from typing import Callable from twisted.conch.insults import helper from twisted.conch.insults.insults import ( BLINK, BOLD, G0, G1, G2, G3, NORMAL, REVERSE_VIDEO, UNDERLINE, modes, privateModes, ) from twisted.python import failure from twisted.trial import unittest WIDTH = 80 HEIGHT = 24 class BufferTests(unittest.TestCase): def setUp(self) -> None: self.term = helper.TerminalBuffer() self.term.connectionMade() def testInitialState(self) -> None: self.assertEqual(self.term.width, WIDTH) self.assertEqual(self.term.height, HEIGHT) self.assertEqual(self.term.__bytes__(), b"\n" * (HEIGHT - 1)) self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def test_initialPrivateModes(self) -> None: """ Verify that only DEC Auto Wrap Mode (DECAWM) and DEC Text Cursor Enable Mode (DECTCEM) are initially in the Set Mode (SM) state. """ self.assertEqual( {privateModes.AUTO_WRAP: True, privateModes.CURSOR_MODE: True}, self.term.privateModes, ) def test_carriageReturn(self) -> None: """ C{"\r"} moves the cursor to the first column in the current row. """ self.term.cursorForward(5) self.term.cursorDown(3) self.assertEqual(self.term.reportCursorPosition(), (5, 3)) self.term.insertAtCursor(b"\r") self.assertEqual(self.term.reportCursorPosition(), (0, 3)) def test_linefeed(self) -> None: """ C{"\n"} moves the cursor to the next row without changing the column. """ self.term.cursorForward(5) self.assertEqual(self.term.reportCursorPosition(), (5, 0)) self.term.insertAtCursor(b"\n") self.assertEqual(self.term.reportCursorPosition(), (5, 1)) def test_newline(self) -> None: """ C{write} transforms C{"\n"} into C{"\r\n"}. """ self.term.cursorForward(5) self.term.cursorDown(3) self.assertEqual(self.term.reportCursorPosition(), (5, 3)) self.term.write(b"\n") self.assertEqual(self.term.reportCursorPosition(), (0, 4)) def test_setPrivateModes(self) -> None: """ Verify that L{helper.TerminalBuffer.setPrivateModes} changes the Set Mode (SM) state to "set" for the private modes it is passed. """ expected = self.term.privateModes.copy() self.term.setPrivateModes([privateModes.SCROLL, privateModes.SCREEN]) expected[privateModes.SCROLL] = True expected[privateModes.SCREEN] = True self.assertEqual(expected, self.term.privateModes) def test_resetPrivateModes(self) -> None: """ Verify that L{helper.TerminalBuffer.resetPrivateModes} changes the Set Mode (SM) state to "reset" for the private modes it is passed. """ expected = self.term.privateModes.copy() self.term.resetPrivateModes([privateModes.AUTO_WRAP, privateModes.CURSOR_MODE]) del expected[privateModes.AUTO_WRAP] del expected[privateModes.CURSOR_MODE] self.assertEqual(expected, self.term.privateModes) def testCursorDown(self) -> None: self.term.cursorDown(3) self.assertEqual(self.term.reportCursorPosition(), (0, 3)) self.term.cursorDown() self.assertEqual(self.term.reportCursorPosition(), (0, 4)) self.term.cursorDown(HEIGHT) self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testCursorUp(self) -> None: self.term.cursorUp(5) self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(20) self.term.cursorUp(1) self.assertEqual(self.term.reportCursorPosition(), (0, 19)) self.term.cursorUp(19) self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorForward(self) -> None: self.term.cursorForward(2) self.assertEqual(self.term.reportCursorPosition(), (2, 0)) self.term.cursorForward(2) self.assertEqual(self.term.reportCursorPosition(), (4, 0)) self.term.cursorForward(WIDTH) self.assertEqual(self.term.reportCursorPosition(), (WIDTH, 0)) def testCursorBackward(self) -> None: self.term.cursorForward(10) self.term.cursorBackward(2) self.assertEqual(self.term.reportCursorPosition(), (8, 0)) self.term.cursorBackward(7) self.assertEqual(self.term.reportCursorPosition(), (1, 0)) self.term.cursorBackward(1) self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorBackward(1) self.assertEqual(self.term.reportCursorPosition(), (0, 0)) def testCursorPositioning(self) -> None: self.term.cursorPosition(3, 9) self.assertEqual(self.term.reportCursorPosition(), (3, 9)) def testSimpleWriting(self) -> None: s = b"Hello, world." self.term.write(s) self.assertEqual(self.term.__bytes__(), s + b"\n" + b"\n" * (HEIGHT - 2)) def testOvertype(self) -> None: s = b"hello, world." self.term.write(s) self.term.cursorBackward(len(s)) self.term.resetModes([modes.IRM]) self.term.write(b"H") self.assertEqual( self.term.__bytes__(), (b"H" + s[1:]) + b"\n" + b"\n" * (HEIGHT - 2) ) def testInsert(self) -> None: s = b"ello, world." self.term.write(s) self.term.cursorBackward(len(s)) self.term.setModes([modes.IRM]) self.term.write(b"H") self.assertEqual( self.term.__bytes__(), (b"H" + s) + b"\n" + b"\n" * (HEIGHT - 2) ) def testWritingInTheMiddle(self) -> None: s = b"Hello, world." self.term.cursorDown(5) self.term.cursorForward(5) self.term.write(s) self.assertEqual( self.term.__bytes__(), b"\n" * 5 + (self.term.fill * 5) + s + b"\n" + b"\n" * (HEIGHT - 7), ) def testWritingWrappedAtEndOfLine(self) -> None: s = b"Hello, world." self.term.cursorForward(WIDTH - 5) self.term.write(s) self.assertEqual( self.term.__bytes__(), s[:5].rjust(WIDTH) + b"\n" + s[5:] + b"\n" + b"\n" * (HEIGHT - 3), ) def testIndex(self) -> None: self.term.index() self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorDown(HEIGHT) self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) self.term.index() self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1)) def testReverseIndex(self) -> None: self.term.reverseIndex() self.assertEqual(self.term.reportCursorPosition(), (0, 0)) self.term.cursorDown(2) self.assertEqual(self.term.reportCursorPosition(), (0, 2)) self.term.reverseIndex() self.assertEqual(self.term.reportCursorPosition(), (0, 1)) def test_nextLine(self) -> None: """ C{nextLine} positions the cursor at the beginning of the row below the current row. """ self.term.nextLine() self.assertEqual(self.term.reportCursorPosition(), (0, 1)) self.term.cursorForward(5) self.assertEqual(self.term.reportCursorPosition(), (5, 1)) self.term.nextLine() self.assertEqual(self.term.reportCursorPosition(), (0, 2)) def testSaveCursor(self) -> None: self.term.cursorDown(5) self.term.cursorForward(7) self.assertEqual(self.term.reportCursorPosition(), (7, 5)) self.term.saveCursor() self.term.cursorDown(7) self.term.cursorBackward(3) self.assertEqual(self.term.reportCursorPosition(), (4, 12)) self.term.restoreCursor() self.assertEqual(self.term.reportCursorPosition(), (7, 5)) def testSingleShifts(self) -> None: self.term.singleShift2() self.term.write(b"Hi") ch = self.term.getCharacter(0, 0) self.assertEqual(ch[0], b"H") self.assertEqual(ch[1].charset, G2) ch = self.term.getCharacter(1, 0) self.assertEqual(ch[0], b"i") self.assertEqual(ch[1].charset, G0) self.term.singleShift3() self.term.write(b"!!") ch = self.term.getCharacter(2, 0) self.assertEqual(ch[0], b"!") self.assertEqual(ch[1].charset, G3) ch = self.term.getCharacter(3, 0) self.assertEqual(ch[0], b"!") self.assertEqual(ch[1].charset, G0) def testShifting(self) -> None: s1 = b"Hello" s2 = b"World" s3 = b"Bye!" self.term.write(b"Hello\n") self.term.shiftOut() self.term.write(b"World\n") self.term.shiftIn() self.term.write(b"Bye!\n") g = G0 h = 0 for s in (s1, s2, s3): for i in range(len(s)): ch = self.term.getCharacter(i, h) self.assertEqual(ch[0], s[i : i + 1]) self.assertEqual(ch[1].charset, g) g = g == G0 and G1 or G0 h += 1 def testGraphicRendition(self) -> None: self.term.selectGraphicRendition(BOLD, UNDERLINE, BLINK, REVERSE_VIDEO) self.term.write(b"W") self.term.selectGraphicRendition(NORMAL) self.term.write(b"X") self.term.selectGraphicRendition(BLINK) self.term.write(b"Y") self.term.selectGraphicRendition(BOLD) self.term.write(b"Z") ch = self.term.getCharacter(0, 0) self.assertEqual(ch[0], b"W") self.assertTrue(ch[1].bold) self.assertTrue(ch[1].underline) self.assertTrue(ch[1].blink) self.assertTrue(ch[1].reverseVideo) ch = self.term.getCharacter(1, 0) self.assertEqual(ch[0], b"X") self.assertFalse(ch[1].bold) self.assertFalse(ch[1].underline) self.assertFalse(ch[1].blink) self.assertFalse(ch[1].reverseVideo) ch = self.term.getCharacter(2, 0) self.assertEqual(ch[0], b"Y") self.assertTrue(ch[1].blink) self.assertFalse(ch[1].bold) self.assertFalse(ch[1].underline) self.assertFalse(ch[1].reverseVideo) ch = self.term.getCharacter(3, 0) self.assertEqual(ch[0], b"Z") self.assertTrue(ch[1].blink) self.assertTrue(ch[1].bold) self.assertFalse(ch[1].underline) self.assertFalse(ch[1].reverseVideo) def testColorAttributes(self) -> None: s1 = b"Merry xmas" s2 = b"Just kidding" self.term.selectGraphicRendition( helper.FOREGROUND + helper.RED, helper.BACKGROUND + helper.GREEN ) self.term.write(s1 + b"\n") self.term.selectGraphicRendition(NORMAL) self.term.write(s2 + b"\n") for i in range(len(s1)): ch = self.term.getCharacter(i, 0) self.assertEqual(ch[0], s1[i : i + 1]) self.assertEqual(ch[1].charset, G0) self.assertFalse(ch[1].bold) self.assertFalse(ch[1].underline) self.assertFalse(ch[1].blink) self.assertFalse(ch[1].reverseVideo) self.assertEqual(ch[1].foreground, helper.RED) self.assertEqual(ch[1].background, helper.GREEN) for i in range(len(s2)): ch = self.term.getCharacter(i, 1) self.assertEqual(ch[0], s2[i : i + 1]) self.assertEqual(ch[1].charset, G0) self.assertFalse(ch[1].bold) self.assertFalse(ch[1].underline) self.assertFalse(ch[1].blink) self.assertFalse(ch[1].reverseVideo) self.assertEqual(ch[1].foreground, helper.WHITE) self.assertEqual(ch[1].background, helper.BLACK) def testEraseLine(self) -> None: s1 = b"line 1" s2 = b"line 2" s3 = b"line 3" self.term.write(b"\n".join((s1, s2, s3)) + b"\n") self.term.cursorPosition(1, 1) self.term.eraseLine() self.assertEqual( self.term.__bytes__(), s1 + b"\n" + b"\n" + s3 + b"\n" + b"\n" * (HEIGHT - 4), ) def testEraseToLineEnd(self) -> None: s = b"Hello, world." self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineEnd() self.assertEqual(self.term.__bytes__(), s[:-5] + b"\n" + b"\n" * (HEIGHT - 2)) def testEraseToLineBeginning(self) -> None: s = b"Hello, world." self.term.write(s) self.term.cursorBackward(5) self.term.eraseToLineBeginning() self.assertEqual( self.term.__bytes__(), s[-4:].rjust(len(s)) + b"\n" + b"\n" * (HEIGHT - 2) ) def testEraseDisplay(self) -> None: self.term.write(b"Hello world\n") self.term.write(b"Goodbye world\n") self.term.eraseDisplay() self.assertEqual(self.term.__bytes__(), b"\n" * (HEIGHT - 1)) def testEraseToDisplayEnd(self) -> None: s1 = b"Hello world" s2 = b"Goodbye world" self.term.write(b"\n".join((s1, s2, b""))) self.term.cursorPosition(5, 1) self.term.eraseToDisplayEnd() self.assertEqual( self.term.__bytes__(), s1 + b"\n" + s2[:5] + b"\n" + b"\n" * (HEIGHT - 3) ) def testEraseToDisplayBeginning(self) -> None: s1 = b"Hello world" s2 = b"Goodbye world" self.term.write(b"\n".join((s1, s2))) self.term.cursorPosition(5, 1) self.term.eraseToDisplayBeginning() self.assertEqual( self.term.__bytes__(), b"\n" + s2[6:].rjust(len(s2)) + b"\n" + b"\n" * (HEIGHT - 3), ) def testLineInsertion(self) -> None: s1 = b"Hello world" s2 = b"Goodbye world" self.term.write(b"\n".join((s1, s2))) self.term.cursorPosition(7, 1) self.term.insertLine() self.assertEqual( self.term.__bytes__(), s1 + b"\n" + b"\n" + s2 + b"\n" + b"\n" * (HEIGHT - 4), ) def testLineDeletion(self) -> None: s1 = b"Hello world" s2 = b"Middle words" s3 = b"Goodbye world" self.term.write(b"\n".join((s1, s2, s3))) self.term.cursorPosition(9, 1) self.term.deleteLine() self.assertEqual( self.term.__bytes__(), s1 + b"\n" + s3 + b"\n" + b"\n" * (HEIGHT - 3) ) class FakeDelayedCall: called = False cancelled = False def __init__( self, fs: FakeScheduler, timeout: float, f: Callable[..., None], a: tuple[object, ...], kw: dict[str, object], ) -> None: self.fs = fs self.timeout = timeout self.f = f self.a = a self.kw = kw def active(self) -> bool: return not (self.cancelled or self.called) def cancel(self) -> None: self.cancelled = True # self.fs.calls.remove(self) def call(self) -> None: self.called = True self.f(*self.a, **self.kw) class FakeScheduler: def __init__(self) -> None: self.calls: list[FakeDelayedCall] = [] def callLater( self, timeout: float, f: Callable[..., None], *a: object, **kw: object ) -> FakeDelayedCall: self.calls.append(FakeDelayedCall(self, timeout, f, a, kw)) return self.calls[-1] class ExpectTests(unittest.TestCase): def setUp(self) -> None: self.term = helper.ExpectableBuffer() self.term.connectionMade() self.fs = FakeScheduler() def testSimpleString(self) -> None: result: list[re.Match[bytes]] = [] d = self.term.expect(b"hello world", timeout=1, scheduler=self.fs) d.addCallback(result.append) self.term.write(b"greeting puny earthlings\n") self.assertFalse(result) self.term.write(b"hello world\n") self.assertTrue(result) self.assertEqual(result[0].group(), b"hello world") self.assertEqual(len(self.fs.calls), 1) self.assertFalse(self.fs.calls[0].active()) def testBrokenUpString(self) -> None: result: list[re.Match[bytes]] = [] d = self.term.expect(b"hello world") d.addCallback(result.append) self.assertFalse(result) self.term.write(b"hello ") self.assertFalse(result) self.term.write(b"worl") self.assertFalse(result) self.term.write(b"d") self.assertTrue(result) self.assertEqual(result[0].group(), b"hello world") def testMultiple(self) -> None: result: list[re.Match[bytes]] = [] d1 = self.term.expect(b"hello ") d1.addCallback(result.append) d2 = self.term.expect(b"world") d2.addCallback(result.append) self.assertFalse(result) self.term.write(b"hello") self.assertFalse(result) self.term.write(b" ") self.assertEqual(len(result), 1) self.term.write(b"world") self.assertEqual(len(result), 2) self.assertEqual(result[0].group(), b"hello ") self.assertEqual(result[1].group(), b"world") def testSynchronous(self) -> None: self.term.write(b"hello world") result: list[re.Match[bytes]] = [] d = self.term.expect(b"hello world") d.addCallback(result.append) self.assertTrue(result) self.assertEqual(result[0].group(), b"hello world") def testMultipleSynchronous(self) -> None: self.term.write(b"goodbye world") result: list[re.Match[bytes]] = [] d1 = self.term.expect(b"bye") d1.addCallback(result.append) d2 = self.term.expect(b"world") d2.addCallback(result.append) self.assertEqual(len(result), 2) self.assertEqual(result[0].group(), b"bye") self.assertEqual(result[1].group(), b"world") def _cbTestTimeoutFailure(self, res: failure.Failure) -> None: self.assertTrue(hasattr(res, "type")) self.assertEqual(res.type, helper.ExpectationTimeout) def testTimeoutFailure(self) -> None: d = self.term.expect(b"hello world", timeout=1, scheduler=self.fs) d.addBoth(self._cbTestTimeoutFailure) self.fs.calls[0].call() def testOverlappingTimeout(self) -> None: self.term.write(b"not zoomtastic") result: list[re.Match[bytes]] = [] d1 = self.term.expect(b"hello world", timeout=1, scheduler=self.fs) d1.addBoth(self._cbTestTimeoutFailure) d2 = self.term.expect(b"zoom") d2.addCallback(result.append) self.fs.calls[0].call() self.assertEqual(len(result), 1) self.assertEqual(result[0].group(), b"zoom") class CharacterAttributeTests(unittest.TestCase): """ Tests for L{twisted.conch.insults.helper.CharacterAttribute}. """ def test_equality(self) -> None: """ L{CharacterAttribute}s must have matching character attribute values (bold, blink, underline, etc) with the same values to be considered equal. """ self.assertEqual(helper.CharacterAttribute(), helper.CharacterAttribute()) self.assertEqual( helper.CharacterAttribute(), helper.CharacterAttribute(charset=G0) ) self.assertEqual( helper.CharacterAttribute( bold=True, underline=True, blink=False, reverseVideo=True, foreground=helper.BLUE, ), helper.CharacterAttribute( bold=True, underline=True, blink=False, reverseVideo=True, foreground=helper.BLUE, ), ) self.assertNotEqual( helper.CharacterAttribute(), helper.CharacterAttribute(charset=G1) ) self.assertNotEqual( helper.CharacterAttribute(bold=True), helper.CharacterAttribute(bold=False) ) def test_wantOneDeprecated(self) -> None: """ L{twisted.conch.insults.helper.CharacterAttribute.wantOne} emits a deprecation warning when invoked. """ # Trigger the deprecation warning. helper._FormattingState().wantOne(bold=True) warningsShown = self.flushWarnings([self.test_wantOneDeprecated]) self.assertEqual(len(warningsShown), 1) self.assertEqual(warningsShown[0]["category"], DeprecationWarning) deprecatedClass = "twisted.conch.insults.helper._FormattingState.wantOne" self.assertEqual( warningsShown[0]["message"], "%s was deprecated in Twisted 13.1.0" % (deprecatedClass), )