Skip to content
Snippets Groups Projects
Commit 6560904b authored by George Nachman's avatar George Nachman Committed by George Nachman
Browse files

Refactor the CSI parser and add a suite of automatic unit tests to measure xterm compatibility.

parent 66065314
No related branches found
No related tags found
No related merge requests found
Showing
with 1470 additions and 0 deletions
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug
from esctypes import Point, Rect
class CHATests(object):
def test_CHA_DefaultParam(self):
"""CHA moves to first column of active line by default."""
esccmd.CUP(Point(5, 3))
esccmd.CHA()
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 3)
def test_CHA_ExplicitParam(self):
"""CHA moves to specified column of active line."""
esccmd.CUP(Point(5, 3))
esccmd.CHA(10)
position = GetCursorPosition()
AssertEQ(position.x(), 10)
AssertEQ(position.y(), 3)
def test_CHA_OutOfBoundsLarge(self):
"""CHA moves as far as possible when given a too-large parameter."""
esccmd.CUP(Point(5, 3))
esccmd.CHA(9999)
position = GetCursorPosition()
width = GetScreenSize().width()
AssertEQ(position.x(), width)
AssertEQ(position.y(), 3)
def test_CHA_ZeroParam(self):
"""CHA moves as far left as possible when given a zero parameter."""
esccmd.CUP(Point(5, 3))
esccmd.CHA(0)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 3)
def test_CHA_IgnoresScrollRegion(self):
"""CHA ignores scroll regions."""
# Set a scroll region.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
esccmd.CUP(Point(5, 3))
esccmd.CHA(1)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 3)
@knownBug(terminal="iTerm2",
reason="iTerm2 has an off-by-one bug in origin mode. 1;1 should go to the origin, but instead it goes one right and one down of the origin.")
def test_CHA_RespectsOriginMode(self):
"""CHA is relative to left margin in origin mode."""
# Set a scroll region.
esccmd.DECSTBM(6, 11)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Move to center of region
esccmd.CUP(Point(7, 9))
position = GetCursorPosition()
AssertEQ(position.x(), 7)
AssertEQ(position.y(), 9)
# Turn on origin mode.
esccmd.DECSET(esccmd.DECOM)
# Move to top but not the left, so CHA has something to do.
esccmd.CUP(Point(2, 1))
# Move to leftmost column in the scroll region.
esccmd.CHA(1)
# Check relative position while still in origin mode.
position = GetCursorPosition()
AssertEQ(position.x(), 1)
escio.Write("X")
# Turn off origin mode. This moves the cursor.
esccmd.DECSET(esccmd.DECOM)
# Turn off scroll regions so checksum can work.
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECLRMM)
# Make sure there's an X at 5,6
AssertScreenCharsInRectEqual(Rect(5, 6, 5, 6),
[ "X" ])
from esc import NUL
import esccmd
import escio
from escutil import AssertEQ, knownBug
from esctypes import Rect
class ChangeColorTests(object):
"""The color numbers correspond to the ANSI colors 0-7, their bright versions
8-15, and if supported, the remainder of the 88-color or 256-color table."""
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_Multiple(self):
"""OSC 4 ; c1 ; spec1 ; s2 ; spec2 ; ST"""
esccmd.ChangeColor("0",
"rgb:f0f0/f0f0/f0f0",
"1",
"rgb:f0f0/0000/0000")
esccmd.ChangeColor("0", "?", "1", "?")
AssertEQ(escio.ReadOSC("4"), ";0;rgb:f0f0/f0f0/f0f0")
AssertEQ(escio.ReadOSC("4"), ";1;rgb:f0f0/0000/0000")
esccmd.ChangeColor("0",
"rgb:8080/8080/8080",
"1",
"rgb:8080/0000/0000")
esccmd.ChangeColor("0", "?", "1", "?")
AssertEQ(escio.ReadOSC("4"), ";0;rgb:8080/8080/8080")
AssertEQ(escio.ReadOSC("4"), ";1;rgb:8080/0000/0000")
def doChangeColorTest(self, c, value, rgb):
esccmd.ChangeColor(c, value)
esccmd.ChangeColor(c, "?")
s = escio.ReadOSC("4")
AssertEQ(s, ";" + c + ";rgb:" + rgb)
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_RGB(self):
self.doChangeColorTest("0", "rgb:f0f0/f0f0/f0f0", "f0f0/f0f0/f0f0")
self.doChangeColorTest("0", "rgb:8080/8080/8080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_Hash3(self):
self.doChangeColorTest("0", "#fff", "f0f0/f0f0/f0f0")
self.doChangeColorTest("0", "#888", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_Hash6(self):
self.doChangeColorTest("0", "#f0f0f0", "f0f0/f0f0/f0f0")
self.doChangeColorTest("0", "#808080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_Hash9(self):
self.doChangeColorTest("0", "#f00f00f00", "f0f0/f0f0/f0f0")
self.doChangeColorTest("0", "#800800800", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_Hash12(self):
self.doChangeColorTest("0", "#f000f000f000", "f0f0/f0f0/f0f0")
self.doChangeColorTest("0", "#800080008000", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_RGBI(self):
self.doChangeColorTest("0", "rgbi:1/1/1", "ffff/ffff/ffff")
self.doChangeColorTest("0", "rgbi:0.5/0.5/0.5", "c1c1/bbbb/bbbb")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_CIEXYZ(self):
self.doChangeColorTest("0", "CIEXYZ:1/1/1", "ffff/ffff/ffff")
self.doChangeColorTest("0", "CIEXYZ:0.5/0.5/0.5", "dddd/b5b5/a0a0")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_CIEuvY(self):
self.doChangeColorTest("0", "CIEuvY:1/1/1", "ffff/ffff/ffff")
self.doChangeColorTest("0", "CIEuvY:0.5/0.5/0.5", "ffff/a3a3/aeae")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_CIExyY(self):
self.doChangeColorTest("0", "CIExyY:1/1/1", "ffff/ffff/ffff")
self.doChangeColorTest("0", "CIExyY:0.5/0.5/0.5", "f7f7/b3b3/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_CIELab(self):
self.doChangeColorTest("0", "CIELab:1/1/1", "6c6c/6767/6767")
self.doChangeColorTest("0", "CIELab:0.5/0.5/0.5", "5252/4f4f/4f4f")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_CIELuv(self):
self.doChangeColorTest("0", "CIELuv:1/1/1", "1616/1414/0e0e")
self.doChangeColorTest("0", "CIELuv:0.5/0.5/0.5", "0e0e/1313/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeColor_TekHVC(self):
self.doChangeColorTest("0", "TekHVC:1/1/1", "1a1a/1313/0f0f")
self.doChangeColorTest("0", "TekHVC:0.5/0.5/0.5", "1111/1313/0e0e")
from esc import NUL
import esccmd
import escio
from escutil import AssertEQ, knownBug
from esctypes import Rect
class ChangeDynamicColorTests(object):
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_Multiple(self):
"""OSC 4 ; c1 ; spec1 ; s2 ; spec2 ; ST"""
esccmd.ChangeDynamicColor("10",
"rgb:f0f0/f0f0/f0f0",
"rgb:f0f0/0000/0000")
esccmd.ChangeDynamicColor("10", "?", "?")
AssertEQ(escio.ReadOSC("10"), ";rgb:f0f0/f0f0/f0f0")
AssertEQ(escio.ReadOSC("11"), ";rgb:f0f0/0000/0000")
esccmd.ChangeDynamicColor("10",
"rgb:8080/8080/8080",
"rgb:8080/0000/0000")
esccmd.ChangeDynamicColor("10", "?", "?")
AssertEQ(escio.ReadOSC("10"), ";rgb:8080/8080/8080")
AssertEQ(escio.ReadOSC("11"), ";rgb:8080/0000/0000")
def doChangeDynamicColorTest(self, c, value, rgb):
esccmd.ChangeDynamicColor(c, value)
esccmd.ChangeDynamicColor(c, "?")
s = escio.ReadOSC(c)
AssertEQ(s, ";rgb:" + rgb)
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_RGB(self):
self.doChangeDynamicColorTest("10", "rgb:f0f0/f0f0/f0f0", "f0f0/f0f0/f0f0")
self.doChangeDynamicColorTest("10", "rgb:8080/8080/8080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_Hash3(self):
self.doChangeDynamicColorTest("10", "#fff", "f0f0/f0f0/f0f0")
self.doChangeDynamicColorTest("10", "#888", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_Hash6(self):
self.doChangeDynamicColorTest("10", "#f0f0f0", "f0f0/f0f0/f0f0")
self.doChangeDynamicColorTest("10", "#808080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_Hash9(self):
self.doChangeDynamicColorTest("10", "#f00f00f00", "f0f0/f0f0/f0f0")
self.doChangeDynamicColorTest("10", "#800800800", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_Hash12(self):
self.doChangeDynamicColorTest("10", "#f000f000f000", "f0f0/f0f0/f0f0")
self.doChangeDynamicColorTest("10", "#800080008000", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_RGBI(self):
self.doChangeDynamicColorTest("10", "rgbi:1/1/1", "ffff/ffff/ffff")
self.doChangeDynamicColorTest("10", "rgbi:0.5/0.5/0.5", "c1c1/bbbb/bbbb")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_CIEXYZ(self):
self.doChangeDynamicColorTest("10", "CIEXYZ:1/1/1", "ffff/ffff/ffff")
self.doChangeDynamicColorTest("10", "CIEXYZ:0.5/0.5/0.5", "dddd/b5b5/a0a0")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_CIEuvY(self):
self.doChangeDynamicColorTest("10", "CIEuvY:1/1/1", "ffff/ffff/ffff")
self.doChangeDynamicColorTest("10", "CIEuvY:0.5/0.5/0.5", "ffff/a3a3/aeae")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_CIExyY(self):
self.doChangeDynamicColorTest("10", "CIExyY:1/1/1", "ffff/ffff/ffff")
self.doChangeDynamicColorTest("10", "CIExyY:0.5/0.5/0.5", "f7f7/b3b3/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_CIELab(self):
self.doChangeDynamicColorTest("10", "CIELab:1/1/1", "6c6c/6767/6767")
self.doChangeDynamicColorTest("10", "CIELab:0.5/0.5/0.5", "5252/4f4f/4f4f")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_CIELuv(self):
self.doChangeDynamicColorTest("10", "CIELuv:1/1/1", "1616/1414/0e0e")
self.doChangeDynamicColorTest("10", "CIELuv:0.5/0.5/0.5", "0e0e/1313/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeDynamicColor_TekHVC(self):
self.doChangeDynamicColorTest("10", "TekHVC:1/1/1", "1a1a/1313/0f0f")
self.doChangeDynamicColorTest("10", "TekHVC:0.5/0.5/0.5", "1111/1313/0e0e")
from esc import NUL
import esccmd
import escio
from escutil import AssertEQ, knownBug
from esctypes import Rect
class ChangeSpecialColorTests(object):
"""Color reporting isn't officially documented for special colors but works
well enough for the test. It responds with mode 4 and a color index 16 higher
than what was queried."""
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_Multiple(self):
"""OSC 4 ; c1 ; spec1 ; s2 ; spec2 ; ST"""
esccmd.ChangeSpecialColor("0",
"rgb:f0f0/f0f0/f0f0",
"1",
"rgb:f0f0/0000/0000")
esccmd.ChangeSpecialColor("0", "?", "1", "?")
AssertEQ(escio.ReadOSC("4"), ";16;rgb:f0f0/f0f0/f0f0")
AssertEQ(escio.ReadOSC("4"), ";17;rgb:f0f0/0000/0000")
esccmd.ChangeSpecialColor("0",
"rgb:8080/8080/8080",
"1",
"rgb:8080/0000/0000")
esccmd.ChangeSpecialColor("0", "?", "1", "?")
AssertEQ(escio.ReadOSC("4"), ";16;rgb:8080/8080/8080")
AssertEQ(escio.ReadOSC("4"), ";17;rgb:8080/0000/0000")
def doChangeSpecialColorTest(self, c, value, rgb):
esccmd.ChangeSpecialColor(c, value)
esccmd.ChangeSpecialColor(c, "?")
s = escio.ReadOSC("4")
AssertEQ(s, ";" + str(int(c) + 16) + ";rgb:" + rgb)
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_RGB(self):
self.doChangeSpecialColorTest("0", "rgb:f0f0/f0f0/f0f0", "f0f0/f0f0/f0f0")
self.doChangeSpecialColorTest("0", "rgb:8080/8080/8080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_Hash3(self):
self.doChangeSpecialColorTest("0", "#fff", "f0f0/f0f0/f0f0")
self.doChangeSpecialColorTest("0", "#888", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_Hash6(self):
self.doChangeSpecialColorTest("0", "#f0f0f0", "f0f0/f0f0/f0f0")
self.doChangeSpecialColorTest("0", "#808080", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_Hash9(self):
self.doChangeSpecialColorTest("0", "#f00f00f00", "f0f0/f0f0/f0f0")
self.doChangeSpecialColorTest("0", "#800800800", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_Hash12(self):
self.doChangeSpecialColorTest("0", "#f000f000f000", "f0f0/f0f0/f0f0")
self.doChangeSpecialColorTest("0", "#800080008000", "8080/8080/8080")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_RGBI(self):
self.doChangeSpecialColorTest("0", "rgbi:1/1/1", "ffff/ffff/ffff")
self.doChangeSpecialColorTest("0", "rgbi:0.5/0.5/0.5", "c1c1/bbbb/bbbb")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_CIEXYZ(self):
self.doChangeSpecialColorTest("0", "CIEXYZ:1/1/1", "ffff/ffff/ffff")
self.doChangeSpecialColorTest("0", "CIEXYZ:0.5/0.5/0.5", "dddd/b5b5/a0a0")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_CIEuvY(self):
self.doChangeSpecialColorTest("0", "CIEuvY:1/1/1", "ffff/ffff/ffff")
self.doChangeSpecialColorTest("0", "CIEuvY:0.5/0.5/0.5", "ffff/a3a3/aeae")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_CIExyY(self):
self.doChangeSpecialColorTest("0", "CIExyY:1/1/1", "ffff/ffff/ffff")
self.doChangeSpecialColorTest("0", "CIExyY:0.5/0.5/0.5", "f7f7/b3b3/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_CIELab(self):
self.doChangeSpecialColorTest("0", "CIELab:1/1/1", "6c6c/6767/6767")
self.doChangeSpecialColorTest("0", "CIELab:0.5/0.5/0.5", "5252/4f4f/4f4f")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_CIELuv(self):
self.doChangeSpecialColorTest("0", "CIELuv:1/1/1", "1616/1414/0e0e")
self.doChangeSpecialColorTest("0", "CIELuv:0.5/0.5/0.5", "0e0e/1313/0e0e")
@knownBug(terminal="iTerm2", reason="Color reporting not implemented.", shouldTry=False)
def test_ChangeSpecialColor_TekHVC(self):
self.doChangeSpecialColorTest("0", "TekHVC:1/1/1", "1a1a/1313/0f0f")
self.doChangeSpecialColorTest("0", "TekHVC:0.5/0.5/0.5", "1111/1313/0e0e")
import esccmd
from esctypes import Point
from escutil import AssertEQ, GetCursorPosition, knownBug
class CHTTests(object):
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't support CHT")
def test_CHT_OneTabStopByDefault(self):
esccmd.CHT()
position = GetCursorPosition()
AssertEQ(position.x(), 9)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't support CHT")
def test_CHT_ExplicitParameter(self):
esccmd.CHT(2)
position = GetCursorPosition()
AssertEQ(position.x(), 17)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't support CHT")
@knownBug(terminal="xterm", reason="xterm respects scrolling regions for CHT")
def test_CHT_IgnoresScrollingRegion(self):
# Set a scroll region.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 30)
# Move to center of region
esccmd.CUP(Point(7, 9))
# Ensure we can tab within the region
esccmd.CHT(2)
position = GetCursorPosition()
AssertEQ(position.x(), 17)
# Ensure that we can tab out of the region
esccmd.CHT(2)
position = GetCursorPosition()
AssertEQ(position.x(), 33)
# Try again, starting before the region.
esccmd.CUP(Point(1, 9))
esccmd.CHT(9)
position = GetCursorPosition()
AssertEQ(position.x(), 73)
import esccmd
from escutil import AssertEQ, GetCursorPosition, GetScreenSize
from esctypes import Point
class CNLTests(object):
def test_CNL_DefaultParam(self):
"""CNL moves the cursor down 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CNL()
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 4)
def test_CNL_ExplicitParam(self):
"""CNL moves the cursor down by the passed-in number of lines."""
esccmd.CUP(Point(6, 3))
esccmd.CNL(2)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 5)
def test_CNL_StopsAtBottomLine(self):
"""CNL moves the cursor down, stopping at the last line."""
esccmd.CUP(Point(6, 3))
height = GetScreenSize().height()
esccmd.CNL(height)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), height)
def test_CNL_StopsAtBottomLineWhenBegunBelowScrollRegion(self):
"""When the cursor starts below the scroll region, CNL moves it down to the
bottom of the screen."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(4, 5)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor below the scroll region
esccmd.CUP(Point(7, 6))
# Move it down by a lot
height = GetScreenSize().height()
esccmd.CNL(height)
# Ensure it stopped at the bottom of the screen
position = GetCursorPosition()
AssertEQ(position.y(), height)
AssertEQ(position.x(), 5)
def test_CNL_StopsAtBottomMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CNL moves it down to the
bottom margin but no farther."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(2, 4)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor within the scroll region
esccmd.CUP(Point(7, 3))
# Move it up by more than the height of the scroll region
esccmd.CNL(99)
# Ensure it stopped at the bottom of the scroll region.
position = GetCursorPosition()
AssertEQ(position.y(), 4)
AssertEQ(position.x(), 5)
import esccmd
from escutil import AssertEQ, GetCursorPosition, GetScreenSize
from esctypes import Point
class CPLTests(object):
def test_CPL_DefaultParam(self):
"""CPL moves the cursor up 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CPL()
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 2)
def test_CPL_ExplicitParam(self):
"""CPL moves the cursor up by the passed-in number of lines."""
esccmd.CUP(Point(6, 5))
esccmd.CPL(2)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 3)
def test_CPL_StopsAtTopLine(self):
"""CPL moves the cursor up, stopping at the last line."""
esccmd.CUP(Point(6, 3))
height = GetScreenSize().height()
esccmd.CPL(height)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 1)
def test_CPL_StopsAtTopLineWhenBegunAboveScrollRegion(self):
"""When the cursor starts above the scroll region, CPL moves it up to the
top of the screen."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(4, 5)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor below the scroll region
esccmd.CUP(Point(7, 3))
# Move it up by a lot
height = GetScreenSize().height()
esccmd.CPL(height)
# Ensure it stopped at the top of the screen
position = GetCursorPosition()
AssertEQ(position.y(), 1)
AssertEQ(position.x(), 5)
def test_CPL_StopsAtTopMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CPL moves it up to the
top margin but no farther."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(2, 4)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor within the scroll region
esccmd.CUP(Point(7, 3))
# Move it up by more than the height of the scroll region
esccmd.CPL(99)
# Ensure it stopped at the top of the scroll region.
position = GetCursorPosition()
AssertEQ(position.y(), 2)
AssertEQ(position.x(), 5)
import esc
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug
from esctypes import Point, Rect
class CRTests(object):
def test_CR_Basic(self):
esccmd.CUP(Point(3, 3))
escio.Write(esc.CR)
AssertEQ(GetCursorPosition(), Point(1, 3))
def test_CR_MovesToLeftMarginWhenRightOfLeftMargin(self):
"""Move the cursor to the left margin if it starts right of it."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
esccmd.CUP(Point(6, 1))
escio.Write(esc.CR)
esccmd.DECRESET(esccmd.DECLRMM)
AssertEQ(GetCursorPosition(), Point(5, 1))
@knownBug(terminal="iTerm2",
reason="iTerm2 incorrectly moves to the left margin.")
def test_CR_MovesToLeftOfScreenWhenLeftOfLeftMargin(self):
"""Move the cursor to the left edge of the screen when it starts of left the margin."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
esccmd.CUP(Point(4, 1))
escio.Write(esc.CR)
esccmd.DECRESET(esccmd.DECLRMM)
AssertEQ(GetCursorPosition(), Point(1, 1))
def test_CR_MovesToLeftMarginWhenLeftOfLeftMarginInOriginMode(self):
"""In origin mode, always go to the left margin, even if the cursor starts left of it."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
esccmd.DECSET(esccmd.DECOM)
esccmd.CUP(Point(4, 1))
escio.Write(esc.CR)
esccmd.DECRESET(esccmd.DECLRMM)
escio.Write("x")
esccmd.DECRESET(esccmd.DECOM)
AssertScreenCharsInRectEqual(Rect(5, 1, 5, 1), [ "x" ])
import esccmd
from escutil import AssertEQ, GetCursorPosition, knownBug
from esctypes import Point
class CUBTests(object):
def test_CUB_DefaultParam(self):
"""CUB moves the cursor left 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CUB()
position = GetCursorPosition()
AssertEQ(position.x(), 4)
AssertEQ(position.y(), 3)
def test_CUB_ExplicitParam(self):
"""CUB moves the cursor left by the passed-in number of columns."""
esccmd.CUP(Point(5, 4))
esccmd.CUB(2)
AssertEQ(GetCursorPosition().x(), 3)
def test_CUB_StopsAtLeftEdge(self):
"""CUB moves the cursor left, stopping at the first column."""
esccmd.CUP(Point(5, 3))
esccmd.CUB(99)
AssertEQ(GetCursorPosition().x(), 1)
@knownBug(terminal="iTerm2",
reason="iTerm2 should stop cursor at the left margin when doing CUB starting left of the region, but it jumps into the region instead.")
def test_CUB_StopsAtLeftEdgeWhenBegunLeftOfScrollRegion(self):
"""When the cursor starts left of the scroll region, CUB moves it left to the
left edge of the screen."""
# Set a scroll region.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor left of the scroll region
esccmd.CUP(Point(4, 3))
# Move it left by a lot
esccmd.CUB(99)
# Ensure it stopped at the left edge of the screen
AssertEQ(GetCursorPosition().x(), 1)
def test_CUB_StopsAtLeftMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CUB moves it left to the
left margin but no farther."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor within the scroll region
esccmd.CUP(Point(7, 3))
# Move it left by more than the height of the scroll region
esccmd.CUB(99)
# Ensure it stopped at the top of the scroll region.
AssertEQ(GetCursorPosition().x(), 5)
import esccmd
from escutil import AssertEQ, GetCursorPosition, GetScreenSize
from esctypes import Point
class CUDTests(object):
def test_CUD_DefaultParam(self):
"""CUD moves the cursor down 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CUD()
position = GetCursorPosition()
AssertEQ(position.x(), 5)
AssertEQ(position.y(), 4)
def test_CUD_ExplicitParam(self):
"""CUD moves the cursor down by the passed-in number of lines."""
esccmd.CUP(Point(1, 3))
esccmd.CUD(2)
AssertEQ(GetCursorPosition().y(), 5)
def test_CUD_StopsAtBottomLine(self):
"""CUD moves the cursor down, stopping at the last line."""
esccmd.CUP(Point(1, 3))
height = GetScreenSize().height()
esccmd.CUD(height)
AssertEQ(GetCursorPosition().y(), height)
def test_CUD_StopsAtBottomLineWhenBegunBelowScrollRegion(self):
"""When the cursor starts below the scroll region, CUD moves it down to the
bottom of the screen."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(4, 5)
# Position the cursor below the scroll region
esccmd.CUP(Point(1, 6))
# Move it down by a lot
height = GetScreenSize().height()
esccmd.CUD(height)
# Ensure it stopped at the bottom of the screen
AssertEQ(GetCursorPosition().y(), height)
def test_CUD_StopsAtBottomMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CUD moves it down to the
bottom margin but no farther."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(2, 4)
# Position the cursor within the scroll region
esccmd.CUP(Point(1, 3))
# Move it up by more than the height of the scroll region
esccmd.CUD(99)
# Ensure it stopped at the bottom of the scroll region.
AssertEQ(GetCursorPosition().y(), 4)
import esccmd
from escutil import AssertEQ, GetCursorPosition, GetScreenSize, knownBug
from esctypes import Point
class CUFTests(object):
def test_CUF_DefaultParam(self):
"""CUF moves the cursor right 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CUF()
position = GetCursorPosition()
AssertEQ(position.x(), 6)
AssertEQ(position.y(), 3)
def test_CUF_ExplicitParam(self):
"""CUF moves the cursor right by the passed-in number of lines."""
esccmd.CUP(Point(1, 2))
esccmd.CUF(2)
AssertEQ(GetCursorPosition().x(), 3)
def test_CUF_StopsAtRightSide(self):
"""CUF moves the cursor right, stopping at the last line."""
esccmd.CUP(Point(1, 3))
width = GetScreenSize().width()
esccmd.CUF(width)
AssertEQ(GetCursorPosition().x(), width)
@knownBug(terminal="iTerm2",
reason="iTerm2 should stop cursor at the right margin when doing CUF inside a scroll region, but it allows it to exit the region.")
def test_CUF_StopsAtRightEdgeWhenBegunRightOfScrollRegion(self):
"""When the cursor starts right of the scroll region, CUF moves it right to the
edge of the screen."""
# Set a scroll region.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor right of the scroll region
esccmd.CUP(Point(12, 3))
AssertEQ(GetCursorPosition().x(), 12)
# Move it right by a lot
width = GetScreenSize().width()
esccmd.CUF(width)
# Ensure it stopped at the right edge of the screen
AssertEQ(GetCursorPosition().x(), width)
def test_CUF_StopsAtRightMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CUF moves it right to the
right margin but no farther."""
# Set a scroll region.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Position the cursor inside the scroll region
esccmd.CUP(Point(7, 3))
# Move it right by a lot
width = GetScreenSize().width()
esccmd.CUF(width)
# Ensure it stopped at the right edge of the screen
AssertEQ(GetCursorPosition().x(), 10)
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug
from esctypes import Point, Rect
class CUPTests(object):
def test_CUP_DefaultParams(self):
"""With no params, CUP moves to 1,1."""
esccmd.CUP(Point(6, 3))
position = GetCursorPosition()
AssertEQ(position.x(), 6)
AssertEQ(position.y(), 3)
esccmd.CUP()
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 1)
def test_CUP_RowOnly(self):
"""Default column is 1."""
esccmd.CUP(Point(6, 3))
position = GetCursorPosition()
AssertEQ(position.x(), 6)
AssertEQ(position.y(), 3)
esccmd.CUP(row=2)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 2)
def test_CUP_ColumnOnly(self):
"""Default row is 1."""
esccmd.CUP(Point(6, 3))
position = GetCursorPosition()
AssertEQ(position.x(), 6)
AssertEQ(position.y(), 3)
esccmd.CUP(col=2)
position = GetCursorPosition()
AssertEQ(position.x(), 2)
AssertEQ(position.y(), 1)
def test_CUP_ZeroIsTreatedAsOne(self):
"""Zero args are treated as 1."""
esccmd.CUP(Point(6, 3))
esccmd.CUP(col=0, row=0)
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 1)
def test_CUP_OutOfBoundsParams(self):
"""With overly large parameters, CUP moves as far as possible down and right."""
size = GetScreenSize()
esccmd.CUP(Point(size.width() + 10, size.height() + 10))
position = GetCursorPosition()
AssertEQ(position.x(), size.width())
AssertEQ(position.y(), size.height())
@knownBug(terminal="iTerm2",
reason="iTerm2 has an off-by-one bug in origin mode. 1;1 should go to the origin, but instead it goes one right and one down of the origin.")
def test_CUP_RespectsOriginMode(self):
"""CUP is relative to margins in origin mode."""
# Set a scroll region.
esccmd.DECSTBM(6, 11)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 10)
# Move to center of region
esccmd.CUP(Point(7, 9))
position = GetCursorPosition()
AssertEQ(position.x(), 7)
AssertEQ(position.y(), 9)
# Turn on origin mode.
esccmd.DECSET(esccmd.DECOM)
# Move to top-left
esccmd.CUP(Point(1, 1))
# Check relative position while still in origin mode.
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 1)
escio.Write("X")
# Turn off origin mode. This moves the cursor.
esccmd.DECSET(esccmd.DECOM)
# Turn off scroll regions so checksum can work.
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECLRMM)
# Make sure there's an X at 5,6
AssertScreenCharsInRectEqual(Rect(5, 6, 5, 6),
[ "X" ])
import esccmd
from escutil import AssertEQ, GetCursorPosition
from esctypes import Point
class CUUTests(object):
def test_CUU_DefaultParam(self):
"""CUU moves the cursor up 1 with no parameter given."""
esccmd.CUP(Point(5, 3))
esccmd.CUU()
position = GetCursorPosition()
AssertEQ(position.x(), 5)
AssertEQ(position.y(), 2)
def test_CUU_ExplicitParam(self):
"""CUU moves the cursor up by the passed-in number of lines."""
esccmd.CUP(Point(1, 3))
esccmd.CUU(2)
AssertEQ(GetCursorPosition().y(), 1)
def test_CUU_StopsAtTopLine(self):
"""CUU moves the cursor up, stopping at the first line."""
esccmd.CUP(Point(1, 3))
esccmd.CUU(99)
AssertEQ(GetCursorPosition().y(), 1)
def test_CUU_StopsAtTopLineWhenBegunAboveScrollRegion(self):
"""When the cursor starts above the scroll region, CUU moves it up to the
top of the screen."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(4, 5)
# Position the cursor above the scroll region
esccmd.CUP(Point(1, 3))
# Move it up by a lot
esccmd.CUU(99)
# Ensure it stopped at the top of the screen
AssertEQ(GetCursorPosition().y(), 1)
def test_CUU_StopsAtTopMarginInScrollRegion(self):
"""When the cursor starts within the scroll region, CUU moves it up to the
top margin but no farther."""
# Set a scroll region. This must be done first because DECSTBM moves the cursor to the origin.
esccmd.DECSTBM(2, 4)
# Position the cursor within the scroll region
esccmd.CUP(Point(1, 3))
# Move it up by more than the height of the scroll region
esccmd.CUU(99)
# Ensure it stopped at the top of the scroll region.
AssertEQ(GetCursorPosition().y(), 2)
import escargs
import esccmd
import escio
from escutil import AssertEQ, knownBug
class DATests(object):
@knownBug(terminal="xterm", reason="xterm double-reports 6.")
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't report 18 or 22.")
def handleDAResponse(self):
params = escio.ReadCSI('c', expected_prefix='?')
if escargs.args.expected_terminal == "xterm":
# This is for a default build. There are various options that could
# change this (disabling ReGIS, etc.)
expected = [ 64, 1, 2, 6, 9, 15, 18, 21, 22 ]
elif escargs.args.expected_terminal == "iTerm2":
# TODO: Determine which VT levels are completely supported an add 6, 62, 63, or 64.
# I believe 18 means we support DECSTB and DECSLRM but I can't find any
# evidence to substantiate this belief.
expected = [ 1, 2, 18, 22 ]
AssertEQ(params, expected)
def test_DA_NoParameter(self):
esccmd.DA()
self.handleDAResponse()
def test_DA_0(self):
esccmd.DA(0)
self.handleDAResponse()
import escargs
import esccmd
import escio
from escutil import AssertEQ, AssertGE, knownBug
class DA2Tests(object):
def handleDA2Response(self):
params = escio.ReadCSI('c', expected_prefix='>')
if escargs.args.expected_terminal == "xterm":
AssertGE(params[0], 41)
AssertGE(params[1], 314)
AssertEQ(len(params), 3)
elif escargs.args.expected_terminal == "iTerm2":
AssertEQ(params[0], 0)
AssertEQ(params[1], 95)
AssertEQ(len(params), 2)
@knownBug(terminal="iTerm2", reason="Extra empty parameter at end of response")
def test_DA2_NoParameter(self):
esccmd.DA2()
self.handleDA2Response()
@knownBug(terminal="iTerm2", reason="Extra empty parameter at end of response")
def test_DA2_0(self):
esccmd.DA2(0)
self.handleDA2Response()
from esc import NUL
import esccmd
import escio
from esctypes import Point, Rect
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug
class DCHTests(object):
def test_DCH_DefaultParam(self):
"""DCH with no parameter should delete one character at the cursor."""
escio.Write("abcd")
esccmd.CUP(Point(2, 1))
esccmd.DCH()
AssertScreenCharsInRectEqual(Rect(1, 1, 4, 1), [ "acd" + NUL ]);
def test_DCH_ExplicitParam(self):
"""DCH deletes the specified number of parameters."""
escio.Write("abcd")
esccmd.CUP(Point(2, 1))
esccmd.DCH(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 4, 1), [ "ad" + NUL * 2 ]);
def test_DCH_RespectsMargins(self):
"""DCH respects left-right margins."""
escio.Write("abcde")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(3, 1))
esccmd.DCH()
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 1), [ "abd" + NUL + "e" ]);
def test_DCH_DeleteAllWithMargins(self):
"""Delete all characters up to right margin."""
escio.Write("abcde")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(3, 1))
esccmd.DCH(99)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 1), [ "ab" + NUL * 2 + "e" ]);
def test_DCH_DoesNothingOutsideLeftRightMargin(self):
"""DCH should do nothing outside left-right margins."""
escio.Write("abcde")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(1, 1))
esccmd.DCH(99)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 1), [ "abcde" ])
@knownBug(terminal="xterm", reason="DCH operates on the current line when outside the scroll region in xterm.")
@knownBug(terminal="xterm", reason="Assertion fires", shouldTry=False)
@knownBug(terminal="iTerm2", reason="DCH operates on the current line when outside the scroll region in iTerm2.")
@knownBug(terminal="Terminal.app", reason="DCH operates on the current line when outside the scroll region in Terminal.app.")
def test_DCH_DoesNothingOutsideTopBottomMargin(self):
"""DCH should do nothing outside top-bottom margins."""
escio.Write("abcde")
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(1, 1))
esccmd.DCH(99)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 1), [ "abcde" ])
from esc import NUL
import escio
from escutil import AssertScreenCharsInRectEqual, knownBug
from esctypes import Rect
class DCSTests(object):
@knownBug(terminal="iTerm2", reason="DCS not parsed correctly.")
def test_DCS_Unrecognized(self):
"""An unrecognized DCS code should be swallowed"""
escio.WriteDCS("z", "0")
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), NUL)
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, Point, Rect, knownBug, optionRequired
class DECALNTests(object):
def test_DECALN_FillsScreen(self):
"""Makes sure DECALN fills the screen with the letter E (could be anything,
but xterm uses E). Testing the whole screen would be slow so we just check
the corners and center."""
esccmd.DECALN()
size = GetScreenSize()
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "E" ])
AssertScreenCharsInRectEqual(Rect(size.width(), 1, size.width(), 1), [ "E" ])
AssertScreenCharsInRectEqual(Rect(1, size.height(), 1, size.height()), [ "E" ])
AssertScreenCharsInRectEqual(Rect(size.width(), size.height(), size.width(), size.height()),
[ "E" ])
AssertScreenCharsInRectEqual(Rect(size.width() / 2,
size.height() / 2,
size.width() / 2,
size.height() / 2),
[ "E" ])
def test_DECALN_MovesCursorHome(self):
esccmd.CUP(Point(5, 5))
esccmd.DECALN()
AssertEQ(GetCursorPosition(), Point(1, 1))
def test_DECALN_ClearsMargins(self):
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 3)
esccmd.DECSTBM(4, 5)
esccmd.DECALN()
# Verify we can pass the top margin
esccmd.CUP(Point(2, 4))
esccmd.CUU()
AssertEQ(GetCursorPosition(), Point(2, 3))
# Verify we can pass the bottom margin
esccmd.CUP(Point(2, 5))
esccmd.CUD()
AssertEQ(GetCursorPosition(), Point(2, 6))
# Verify we can pass the left margin
esccmd.CUP(Point(2, 4))
esccmd.CUB()
AssertEQ(GetCursorPosition(), Point(1, 4))
# Verify we can pass the right margin
esccmd.CUP(Point(3, 4))
esccmd.CUF()
AssertEQ(GetCursorPosition(), Point(4, 4))
from esc import blank
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, Point, Rect, intentionalDeviationFromSpec, knownBug, optionRequired, vtLevel
class DECBITests(object):
"""Move cursor back or scroll data within margins right."""
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECBI_Basic(self):
esccmd.CUP(Point(5, 6))
esccmd.DECBI()
AssertEQ(GetCursorPosition(), Point(4, 6))
@knownBug(terminal="iTerm2", reason="Not implemented.", noop=True)
@vtLevel(4)
def test_DECBI_NoWrapOnLeftEdge(self):
esccmd.CUP(Point(1, 2))
esccmd.DECBI()
AssertEQ(GetCursorPosition(), Point(1, 2))
@knownBug(terminal="iTerm2", reason="Not implemented.")
@vtLevel(4)
def test_DECBI_Scrolls(self):
strings = [ "abcde",
"fghij",
"klmno",
"pqrst",
"uvwxy" ]
y = 3
for s in strings:
esccmd.CUP(Point(2, y))
escio.Write(s)
y += 1
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(3, 5)
esccmd.DECSTBM(4, 6)
esccmd.CUP(Point(3, 5))
esccmd.DECBI()
AssertScreenCharsInRectEqual(Rect(2, 3, 6, 7),
[ "abcde",
"f" + blank() + "ghj",
"k" + blank() + "lmo",
"p" + blank() + "qrt",
"uvwxy" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented.")
@knownBug(terminal="xterm",
reason="While the docs for DECBI are self-contradictory, I believe the cursor should move in this case. xterm does not move it.")
def test_DECBI_LeftOfMargin(self):
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(3, 5)
esccmd.CUP(Point(2, 1))
esccmd.DECBI()
AssertEQ(GetCursorPosition(), Point(1, 1))
@knownBug(terminal="iTerm2", reason="Not implemented.")
@vtLevel(4)
@intentionalDeviationFromSpec(terminal="xterm",
reason="The spec says 'If the cursor is at the left border of the page when the terminal receives DECBI, then the terminal ignores DECBI', but that only makes sense when the left margin is not 0.")
def test_DECBI_WholeScreenScrolls(self):
"""The spec is confusing and contradictory. It first says "If the cursor is
at the left margin, then all screen data within the margin moves one column
to the right" and then says "DECBI is not affected by the margins." I don't
know what they could mean by the second part."""
escio.Write("x")
esccmd.CUP(Point(1, 1))
esccmd.DECBI()
AssertScreenCharsInRectEqual(Rect(1, 1, 2, 1), [ blank() + "x" ])
from esc import NUL, CR, LF
import esccmd
import escio
import esclog
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug, vtLevel
from esctypes import Point, Rect
class DECCRATests(object):
"""Copy rectangular area."""
def prepare(self):
esccmd.CUP(Point(1, 1))
escio.Write("abcdefgh" + CR + LF)
escio.Write("ijklmnop" + CR + LF)
escio.Write("qrstuvwx" + CR + LF)
escio.Write("yz012345" + CR + LF)
escio.Write("ABCDEFGH" + CR + LF)
escio.Write("IJKLMNOP" + CR + LF)
escio.Write("QRSTUVWX" + CR + LF)
escio.Write("YZ6789!@" + CR + LF)
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_nonOverlappingSourceAndDest(self):
self.prepare()
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1,
dest_top=5,
dest_left=5,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrstuvwx",
"yz012345",
"ABCDjklH",
"IJKLrstP",
"QRSTz01X",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_overlappingSourceAndDest(self):
self.prepare()
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1,
dest_top=3,
dest_left=3,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrjklvwx",
"yzrst345",
"ABz01FGH",
"IJKLMNOP",
"QRSTUVWX",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="Crashes. Bug reported Feb 11, 2015.",
shouldTry=False)
def test_DECCRA_destinationPartiallyOffscreen(self):
self.prepare()
size = GetScreenSize()
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1,
dest_top=size.height() - 1,
dest_left=size.width() - 1,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(size.width() - 1,
size.height() - 1,
size.width(),
size.height()),
[ "jk",
"rj" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_defaultValuesInSource(self):
self.prepare()
esccmd.DECCRA(source_bottom=2,
source_right=2,
dest_top=5,
dest_left=5,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrstuvwx",
"yz012345",
"ABCDabGH",
"IJKLijOP",
"QRSTUVWX",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_defaultValuesInDest(self):
self.prepare()
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1)
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "jkldefgh",
"rstlmnop",
"z01tuvwx",
"yz012345",
"ABCDEFGH",
"IJKLMNOP",
"QRSTUVWX",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented", noop=True)
def test_DECCRA_invalidSourceRectDoesNothing(self):
self.prepare()
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=1,
source_right=1,
source_page=1,
dest_top=5,
dest_left=5,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrstuvwx",
"yz012345",
"ABCDEFGH",
"IJKLMNOP",
"QRSTUVWX",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_respectsOriginMode(self):
self.prepare()
# Set margins at 2, 2
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 9)
esccmd.DECSTBM(2, 9)
# Turn on origin mode
esccmd.DECSET(esccmd.DECOM)
# Copy from 1,1 to 4,4 - with origin mode, that's 2,2 to 5,5
esccmd.DECCRA(source_top=1,
source_left=1,
source_bottom=3,
source_right=3,
source_page=1,
dest_top=4,
dest_left=4,
dest_page=1)
# Turn off margins and origin mode
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECOM)
# See what happened.
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrstuvwx",
"yz012345",
"ABCDjklH",
"IJKLrstP",
"QRSTz01X",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_ignoresMargins(self):
self.prepare()
# Set margins
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(3, 6)
esccmd.DECSTBM(3, 6)
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1,
dest_top=5,
dest_left=5,
dest_page=1)
# Remove margins
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
# Did it ignore the margins?
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 8),
[ "abcdefgh",
"ijklmnop",
"qrstuvwx",
"yz012345",
"ABCDjklH",
"IJKLrstP",
"QRSTz01X",
"YZ6789!@" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECCRA_overlyLargeSourceClippedToScreenSize(self):
size = GetScreenSize()
# Put ab, cX in the bottom right
esccmd.CUP(Point(size.width() - 1, size.height() - 1))
escio.Write("ab")
esccmd.CUP(Point(size.width() - 1, size.height()))
escio.Write("cX")
# Copy a 2x2 block starting at the X to the a
esccmd.DECCRA(source_top=size.height(),
source_left=size.width(),
source_bottom=size.height() + 1,
source_right=size.width() + 1,
source_page=1,
dest_top=size.height() - 1,
dest_left=size.width() - 1,
dest_page=1)
AssertScreenCharsInRectEqual(Rect(size.width() - 1,
size.height() - 1,
size.width(),
size.height()),
[ "Xb", "cX" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented", noop=True)
def test_DECCRA_cursorDoesNotMove(self):
# Make sure something is on screen (so the test is more deterministic)
self.prepare()
# Place the cursor
position = Point(3, 4)
esccmd.CUP(position)
# Copy a block
esccmd.DECCRA(source_top=2,
source_left=2,
source_bottom=4,
source_right=4,
source_page=1,
dest_top=5,
dest_left=5,
dest_page=1)
# Make sure the cursor is where we left it.
AssertEQ(GetCursorPosition(), position)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment