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 2988 additions and 0 deletions
from esc import NUL, CR, LF
import escargs
import esccmd
import escio
from escutil import AssertEQ, GetCursorPosition, GetScreenSize, AssertScreenCharsInRectEqual, knownBug, vtLevel
from esctypes import Point, Rect
import time
class DECDCTests(object):
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECDC")
def test_DECDC_DefaultParam(self):
"""Test DECDC with default parameter """
esccmd.CUP(Point(1, 1))
AssertEQ(GetCursorPosition().x(), 1)
escio.Write("abcdefg" + CR + LF + "ABCDEFG")
esccmd.CUP(Point(2, 1))
AssertEQ(GetCursorPosition().x(), 2)
esccmd.DECDC()
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 2),
[ "acdefg" + NUL,
"ACDEFG" + NUL ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECDC")
def test_DECDC_ExplicitParam(self):
"""Test DECDC with explicit parameter. Also verifies lines above and below
the cursor are affected."""
esccmd.CUP(Point(1, 1))
AssertEQ(GetCursorPosition().x(), 1)
escio.Write("abcdefg" + CR + LF + "ABCDEFG" + CR + LF + "zyxwvut")
esccmd.CUP(Point(2, 2))
AssertEQ(GetCursorPosition().x(), 2)
esccmd.DECDC(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 3),
[ "adefg" + NUL * 2,
"ADEFG" + NUL * 2,
"zwvut" + NUL * 2 ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECDC_CursorWithinTopBottom(self):
"""DECDC should only affect rows inside region."""
esccmd.DECSTBM()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(1, 20)
# Write four lines. The middle two will be in the scroll region.
esccmd.CUP(Point(1, 1))
escio.Write("abcdefg" + CR + LF +
"ABCDEFG" + CR + LF +
"zyxwvut" + CR + LF +
"ZYXWVUT")
# Define a scroll region. Place the cursor in it. Insert a column.
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(2, 2))
esccmd.DECDC(2)
# Remove scroll region and see if it worked.
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 4),
[ "abcdefg",
"ADEFG" + NUL * 2,
"zwvut" + NUL * 2,
"ZYXWVUT" ])
@vtLevel(4)
@knownBug(terminal="iTerm2",reason="Not implemented", noop=True)
@knownBug(terminal="xterm",
reason="xterm requires left-right mode for DECDC",
noop=True)
def test_DECDC_IsNoOpWhenCursorBeginsOutsideScrollRegion(self):
"""Ensure DECDC does nothing when the cursor starts out outside the scroll
region."""
esccmd.CUP(Point(1, 1))
escio.Write("abcdefg" + CR + LF + "ABCDEFG")
# Set margin: from columns 2 to 5
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 5)
# Position cursor outside margins
esccmd.CUP(Point(1, 1))
# Insert blanks
esccmd.DECDC(10)
# Ensure nothing happened.
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 2),
[ "abcdefg",
"ABCDEFG" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECDC")
def test_DECDC_DeleteAll(self):
"""Test DECDC behavior when deleting more columns than are available."""
width = GetScreenSize().width()
s = "abcdefg"
startX = width - len(s) + 1
esccmd.CUP(Point(startX, 1))
escio.Write(s)
esccmd.CUP(Point(startX, 2))
escio.Write(s.upper())
esccmd.CUP(Point(startX + 1, 1))
esccmd.DECDC(width + 10)
AssertScreenCharsInRectEqual(Rect(startX, 1, width, 2),
[ "a" + NUL * 6,
"A" + NUL * 6 ])
# Ensure there is no wrap-around.
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ NUL, NUL ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECDC_DeleteWithLeftRightMargins(self):
"""Test DECDC when cursor is within the scroll region."""
esccmd.CUP(Point(1, 1))
s = "abcdefg"
escio.Write(s)
esccmd.CUP(Point(1, 2))
escio.Write(s.upper())
# Set margin: from columns 2 to 5
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 5)
# Position cursor inside margins
esccmd.CUP(Point(3, 1))
# Insert blank
esccmd.DECDC()
# Ensure the 'e' gets dropped.
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 2),
[ "abde" + NUL + "fg",
"ABDE" + NUL + "FG" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECDC_DeleteAllWithLeftRightMargins(self):
"""Test DECDC when cursor is within the scroll region."""
esccmd.CUP(Point(1, 1))
s = "abcdefg"
escio.Write(s)
esccmd.CUP(Point(1, 2))
escio.Write(s.upper())
# Set margin: from columns 2 to 5
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 5)
# Position cursor inside margins
esccmd.CUP(Point(3, 1))
# Insert blank
esccmd.DECDC(99)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 2),
[ "ab" + NUL * 3 + "fg",
"AB" + NUL * 3 + "FG" ])
from esc import NUL
import esccmd
import escio
import esclog
from escutil import AssertEQ, AssertScreenCharsInRectEqual, AssertTrue, GetScreenSize, knownBug
from esctypes import Point, Rect
class DECDSRTests(object):
def getVTLevel(self):
esccmd.DA2()
params = escio.ReadCSI('c', expected_prefix='>')
vtLevel = params[0]
if vtLevel < 18:
return 2
elif vtLevel <= 24:
return 3
else:
return 4
# TODO: It looks like this code didn't exist until at least VT level 3 was
# introduced, so I'm not sure it makes sense to test it in a term that
# returns a lower VT level. I plan to go back and update all the tests for
# different VT level capabilities.
def test_DECDSR_DECXCPR(self):
"""DECXCPR reports the cursor position. Response is:
CSI ? Pl ; Pc ; Pr R
Pl - line
Pc - column
Pr - page"""
# First, get the VT level.
vtLevel = self.getVTLevel()
esccmd.CUP(Point(5, 6))
esccmd.DECDSR(esccmd.DECXCPR)
params = escio.ReadCSI('R', expected_prefix='?')
if vtLevel >= 4:
# VT400+
# Last arg is page, which is always 1 (at least in xterm, and I think
# that's reasonable in all modern terminals, which won't have a direct
# notion of a page.)
AssertEQ(params, [ 6, 5, 1 ])
else:
AssertEQ(params, [ 6, 5 ])
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRPrinterPort(self):
"""Requests printer status. The allowed responses are:
CSI ? Pn n
Where Pn is:
10 - Ready
11 - Not ready
13 - No printer
18 - Busy
19 - Assigned to other session.
There's no way for the test to know what the actual printer status is,
but the response should be legal."""
esccmd.DECDSR(esccmd.DSRPrinterPort)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(len(params), 1)
AssertTrue(params[0] in [ 10, 11, 13, 18, 19 ])
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRUDKLocked(self):
"""Tests if user-defined keys are locked or unlocked. The allowed repsonses are:
CSI ? Pn n
Where Pn is:
20 - Unlocked
21 - Locked
This test simply ensures the value is legal. It should be extended to
ensure that when locked UDKs are not settable, and when unlocked that UDKs
are settable."""
esccmd.DECDSR(esccmd.DSRUDKLocked)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(len(params), 1)
AssertTrue(params[0] in [ 20, 21 ])
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRKeyboard(self):
"""Gets info about the keyboard. The response is:
CSI ? 27; Pn; Pst; Ptyp n
Where
Pn - Keyboard language
0 - Not known
1 - North American
2...19, 22, 28, 29...31, 33, 35, 36, 38...40 - Various other legal values
Pst - Keyboard status - Per the VT 510 manual, this is level 4 only.
However, it is documented in "VT330/VT340 Programmer Reference Manual
Volume 1: Text Programming".
0 - Ready
3 - No keyboard
8 - Keyboard busy in other session
Ptyp - Keyboard type - VT level 4 only
0 - LK201 # DEC 420
1 - LK401 # DEC 420
4 - LK450 # DEC 510
5 - PCXAL # DEC 510"""
# First get the VT level with a DA2
vtLevel = self.getVTLevel()
esccmd.DECDSR(esccmd.DSRKeyboard)
params = escio.ReadCSI('n', expected_prefix='?')
if vtLevel <= 2:
# VT240 or earlier
AssertEQ(len(params), 2)
elif vtLevel == 3:
# VT340 or earlier
AssertEQ(len(params), 3)
else:
# VT420+
AssertEQ(len(params), 4)
AssertEQ(params[0], 27)
if len(params) > 1:
AssertTrue(params[1] in [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 28, 29, 30,
31, 33, 35, 36, 38, 39, 40 ])
if len(params) > 2:
AssertTrue(params[2] in [ 0, 3, 8 ])
if len(params) > 3:
AssertTrue(params[3] in [ 0, 1, 4, 5 ])
def doLocatorStatusTest(self, code):
"""I couldn't find docs on these codes outside xterm. 53 and 55 seem to be
the same. Returns 50 if no locator, 53 if available."""
esccmd.DECDSR(code)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(len(params), 1)
AssertTrue(params[0] in [ 50, 53, 55 ])
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRDECLocatorStatus(self):
self.doLocatorStatusTest(esccmd.DSRDECLocatorStatus)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRXtermLocatorStatus(self):
self.doLocatorStatusTest(esccmd.DSRXtermLocatorStatus)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_LocatorType(self):
"""Get the type of the locator (pointing device.)
0 - unknown (not documented)
1 - mouse
2 - tablet"""
esccmd.DECDSR(esccmd.DSRLocatorId)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(params[0], 57)
AssertTrue(params[1] in [ 0, 1, 2 ])
# 1 = mouse, 2 = tablet, pretty sure 1 is the only reasonable response.
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DECMSR(self):
"""Get space available for macros. This test assumes it's always 0."""
esccmd.DECDSR(esccmd.DECMSR)
params = escio.ReadCSI('*{')
# Assume the terminal being tested doesn't support macros. May need to add
# code some day for a more capable terminal.
AssertEQ(len(params), 1)
AssertEQ(params[0], 0)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DECCKSR(self):
"""Get checksum of macros. This test assumes it's always 0."""
esccmd.DECDSR(Ps=esccmd.DECCKSR, Pid=123)
value = escio.ReadDCS()
AssertEQ(value, "123!~0000")
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRDataIntegrity(self):
"""Check for link errors. Should always report OK."""
esccmd.DECDSR(esccmd.DSRIntegrityReport)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(len(params), 1)
AssertEQ(params[0], 70)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECDSR_DSRMultipleSessionStatus(self):
"""Checks on the status of multiple sessons. SSU refers to some proprietary
DEC technology that multilexes multiple sessions over a single link using
the "TDSMP" protocol. Lots of detail here:
http://paperlined.org/apps/terminals/control_characters/TDSMP.html
It's safe to assume TDSMP is dead and buried.
CSI ? 80 ; Ps2 n
Multiple sessions are operating using the session support utility (SSU)
and the current SSU state is enabled. Ps2 indicates the maximum number of
sessions available. Default: Ps2 = 2
CSI ? 81 ; Ps2 n
The terminal is currently configured for multiple sessions using SSU but
the current SSU state is pending. Ps2 indicates the maximum number of
sessions available. Default: Ps2 = 2
CSI ? 83 n
The terminal is not configured for multiple-session operation.
CSI ? 87 n
Multiple sessions are operating using a separate physical line for each
session, not SSU."""
esccmd.DECDSR(esccmd.DSRMultipleSessionStatus)
params = escio.ReadCSI('n', expected_prefix='?')
AssertEQ(len(params), 1)
# 83 and 87 both seem like reasonable responses for a terminal that
# supports tabs or windows.
AssertTrue(params[0] in [ 83, 87 ])
import tests.fill_rectangle
import esc
import escargs
import esccmd
from escutil import knownBug
class DECERATests(tests.fill_rectangle.FillRectangleTests):
def fill(self, top=None, left=None, bottom=None, right=None):
esccmd.DECERA(top, left, bottom, right)
def characters(self, point, count):
return esc.blank() * count
def test_DECERA_basic(self):
self.fillRectangle_basic()
def test_DECERA_invalidRectDoesNothing(self):
self.fillRectangle_invalidRectDoesNothing()
@knownBug(terminal="xterm",
reason="xterm doesn't accept all default params for DECERA, although it does work if there is a single semicolon")
def test_DECERA_defaultArgs(self):
self.fillRectangle_defaultArgs()
def test_DECERA_respectsOriginMode(self):
self.fillRectangle_respectsOriginMode()
def test_DECERA_overlyLargeSourceClippedToScreenSize(self):
self.fillRectangle_overlyLargeSourceClippedToScreenSize()
def test_DECERA_cursorDoesNotMove(self):
self.fillRectangle_cursorDoesNotMove()
def test_DECERA_ignoresMargins(self):
self.fillRectangle_ignoresMargins()
from esc import blank, NUL
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, Point, Rect, intentionalDeviationFromSpec, knownBug, optionRequired, vtLevel
class DECFITests(object):
"""Move cursor forward or scroll data within margins right."""
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECFI_Basic(self):
esccmd.CUP(Point(5, 6))
esccmd.DECFI()
AssertEQ(GetCursorPosition(), Point(6, 6))
@knownBug(terminal="iTerm2", reason="Not implemented.", noop=True)
@vtLevel(4)
def test_DECFI_NoWrapOnRightEdge(self):
size = GetScreenSize()
esccmd.CUP(Point(size.width(), 2))
esccmd.DECFI()
AssertEQ(GetCursorPosition(), Point(size.width(), 2))
@knownBug(terminal="iTerm2", reason="Not implemented.")
@vtLevel(4)
def test_DECFI_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(5, 5))
esccmd.DECFI()
# It is out of character for xterm to use NUL in the middle of the line,
# but not terribly important, and not worth marking as a bug. I mentioned
# it to TED.
AssertScreenCharsInRectEqual(Rect(2, 3, 6, 7),
[ "abcde",
"fhi" + NUL + "j",
"kmn" + NUL + "o",
"prs" + NUL + "t",
"uvwxy" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented.")
@knownBug(terminal="xterm",
reason="While the docs for DECFI are self-contradictory, I believe the cursor should move in this case. xterm does not move it.")
def test_DECFI_RightOfMargin(self):
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(3, 5)
esccmd.CUP(Point(6, 1))
esccmd.DECFI()
AssertEQ(GetCursorPosition(), Point(7, 1))
@knownBug(terminal="iTerm2", reason="Not implemented.")
@vtLevel(4)
@intentionalDeviationFromSpec(terminal="xterm",
reason="The spec says 'If the cursor is at the right border of the page when the terminal receives DECFI, then the terminal ignores DECFI', but that only makes sense when the right margin is not at the right edge of the screen.")
def test_DECFI_WholeScreenScrolls(self):
"""The spec is confusing and contradictory. It first says "If the cursor is
at the right margin, then all screen data within the margin moves one column
to the left" and then says "DECFI is not affected by the margins." I don't
know what they could mean by the second part."""
size = GetScreenSize()
esccmd.CUP(Point(size.width(), 1))
escio.Write("x")
esccmd.DECFI()
AssertScreenCharsInRectEqual(Rect(size.width() - 1, 1, size.width(), 1), [ "x" + NUL ])
import tests.fill_rectangle
import esc
import esccmd
CHARACTER = "%"
class DECFRATests(tests.fill_rectangle.FillRectangleTests):
def fill(self, top=None, left=None, bottom=None, right=None):
esccmd.DECFRA(str(ord(CHARACTER)), top, left, bottom, right)
def characters(self, point, count):
return CHARACTER * count
def test_DECFRA_basic(self):
self.fillRectangle_basic()
def test_DECFRA_invalidRectDoesNothing(self):
self.fillRectangle_invalidRectDoesNothing()
def test_DECFRA_defaultArgs(self):
self.fillRectangle_defaultArgs()
def test_DECFRA_respectsOriginMode(self):
self.fillRectangle_respectsOriginMode()
def test_DECFRA_overlyLargeSourceClippedToScreenSize(self):
self.fillRectangle_overlyLargeSourceClippedToScreenSize()
def test_DECFRA_cursorDoesNotMove(self):
self.fillRectangle_cursorDoesNotMove()
def test_DECFRA_ignoresMargins(self):
self.fillRectangle_ignoresMargins()
from esc import NUL, CR, LF, blank
import escargs
import esccmd
import escio
from escutil import AssertEQ, GetCursorPosition, GetScreenSize, AssertScreenCharsInRectEqual, knownBug, vtLevel
from esctypes import Point, Rect
import time
class DECICTests(object):
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECIC")
def test_DECIC_DefaultParam(self):
""" Test DECIC with default parameter """
esccmd.CUP(Point(1, 1))
AssertEQ(GetCursorPosition().x(), 1)
escio.Write("abcdefg" + CR + LF + "ABCDEFG")
esccmd.CUP(Point(2, 1))
AssertEQ(GetCursorPosition().x(), 2)
esccmd.DECIC()
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 2),
[ "a" + blank() + "bcdefg",
"A" + blank() + "BCDEFG" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECIC")
def test_DECIC_ExplicitParam(self):
"""Test DECIC with explicit parameter. Also verifies lines above and below
the cursor are affected."""
esccmd.CUP(Point(1, 1))
AssertEQ(GetCursorPosition().x(), 1)
escio.Write("abcdefg" + CR + LF + "ABCDEFG" + CR + LF + "zyxwvut")
esccmd.CUP(Point(2, 2))
AssertEQ(GetCursorPosition().x(), 2)
esccmd.DECIC(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 9, 3),
[ "a" + blank() * 2 + "bcdefg",
"A" + blank() * 2 + "BCDEFG",
"z" + blank() * 2 + "yxwvut" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECIC_CursorWithinTopBottom(self):
"""DECIC should only affect rows inside region."""
esccmd.DECSTBM()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(1, 20)
# Write four lines. The middle two will be in the scroll region.
esccmd.CUP(Point(1, 1))
escio.Write("abcdefg" + CR + LF +
"ABCDEFG" + CR + LF +
"zyxwvut" + CR + LF +
"ZYXWVUT")
# Define a scroll region. Place the cursor in it. Insert a column.
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(2, 2))
esccmd.DECIC(2)
# Remove scroll region and see if it worked.
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 9, 4),
[ "abcdefg" + NUL * 2,
"A" + blank() * 2 + "BCDEFG",
"z" + blank() * 2 + "yxwvut",
"ZYXWVUT" + NUL * 2 ])
@vtLevel(4)
@knownBug(terminal="iTerm2",reason="Not implemented", noop=True)
@knownBug(terminal="xterm",
reason="xterm requires left-right mode for DECIC",
noop=True)
def test_DECIC_IsNoOpWhenCursorBeginsOutsideScrollRegion(self):
"""Ensure DECIC does nothing when the cursor starts out outside the scroll
region."""
esccmd.CUP(Point(1, 1))
escio.Write("abcdefg" + CR + LF + "ABCDEFG")
# Set margin: from columns 2 to 5
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 5)
# Position cursor outside margins
esccmd.CUP(Point(1, 1))
# Insert blanks
esccmd.DECIC(10)
# Ensure nothing happened.
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 2),
[ "abcdefg",
"ABCDEFG" ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECIC")
def test_DECIC_ScrollOffRightEdge(self):
"""Test DECIC behavior when pushing text off the right edge. """
width = GetScreenSize().width()
s = "abcdefg"
startX = width - len(s) + 1
esccmd.CUP(Point(startX, 1))
escio.Write(s)
esccmd.CUP(Point(startX, 2))
escio.Write(s.upper())
esccmd.CUP(Point(startX + 1, 1))
esccmd.DECIC()
AssertScreenCharsInRectEqual(Rect(startX, 1, width, 2),
[ "a" + blank() + "bcdef",
"A" + blank() + "BCDEF" ])
# Ensure there is no wrap-around.
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ NUL, NUL ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
@knownBug(terminal="xterm", reason="xterm requires left-right mode for DECIC")
def test_DECIC_ScrollEntirelyOffRightEdge(self):
"""Test DECIC behavior when pushing text off the right edge. """
width = GetScreenSize().width()
esccmd.CUP(Point(1, 1))
escio.Write("x" * width)
esccmd.CUP(Point(1, 2))
escio.Write("x" * width)
esccmd.CUP(Point(1, 1))
esccmd.DECIC(width)
expectedLine = blank() * width
AssertScreenCharsInRectEqual(Rect(1, 1, width, 2),
[ expectedLine, expectedLine ])
# Ensure there is no wrap-around.
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3),
[ blank(), blank() ])
@vtLevel(4)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECIC_ScrollOffRightMarginInScrollRegion(self):
"""Test DECIC when cursor is within the scroll region."""
esccmd.CUP(Point(1, 1))
s = "abcdefg"
escio.Write(s)
esccmd.CUP(Point(1, 2))
escio.Write(s.upper())
# Set margin: from columns 2 to 5
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 5)
# Position cursor inside margins
esccmd.CUP(Point(3, 1))
# Insert blank
esccmd.DECIC()
# Ensure the 'e' gets dropped.
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, len(s), 2),
[ "ab" + blank() + "cdfg",
"AB" + blank() + "CDFG" ])
from esc import NUL, ST, S8C1T, S7C1T
import escargs
import esccmd
import escio
from escutil import AssertTrue, knownBug, optionRequired
class DECIDTests(object):
@knownBug(terminal="iTerm2", reason="Not implemented.", shouldTry=False)
def test_DECID_Basic(self):
esccmd.DECID()
params = escio.ReadCSI("c", expected_prefix="?")
AssertTrue(len(params) > 0)
@optionRequired(terminal="xterm", option=escargs.DISABLE_WIDE_CHARS)
@knownBug(terminal="iTerm2", reason="8-bit controls not implemented.")
def test_DECID_8bit(self):
escio.use8BitControls = True
escio.Write(S8C1T)
esccmd.DECID()
params = escio.ReadCSI("c", expected_prefix="?")
AssertTrue(len(params) > 0)
escio.Write(S7C1T)
escio.use8BitControls = False
import tests.save_restore_cursor
import esccmd
class DECRCTests(tests.save_restore_cursor.SaveRestoreCursorTests):
def saveCursor(self):
esccmd.DECSC()
def restoreCursor(self):
esccmd.DECRC()
from esc import NUL
import escargs
import esccmd
import escio
import esclog
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetScreenSize, knownBug, optionRequired, vtLevel
from esctypes import Point, Rect
class DECRQMTests(object):
"""DECANM is not tested because there doesn't seem to be any way to
exit VT52 mode and subsequent tests are broken."""
def requestAnsiMode(self, mode):
esccmd.DECRQM(mode, DEC=False)
return escio.ReadCSI('$y')
def requestDECMode(self, mode):
esccmd.DECRQM(mode, DEC=True)
return escio.ReadCSI('$y', '?')
def doModifiableAnsiTest(self, mode):
before = self.requestAnsiMode(mode)
if before[1] == 2:
esccmd.SM(mode)
AssertEQ(self.requestAnsiMode(mode), [ mode, 1 ])
esccmd.RM(mode)
AssertEQ(self.requestAnsiMode(mode), [ mode, 2 ])
else:
esccmd.RM(mode)
AssertEQ(self.requestAnsiMode(mode), [ mode, 2 ])
esccmd.SM(mode)
AssertEQ(self.requestAnsiMode(mode), [ mode, 1 ])
def doPermanentlyResetAnsiTest(self, mode):
AssertEQ(self.requestAnsiMode(mode), [ mode, 4 ])
def doModifiableDecTest(self, mode):
before = self.requestDECMode(mode)
if before[1] == 2:
esccmd.DECSET(mode)
AssertEQ(self.requestDECMode(mode), [ mode, 1 ])
esccmd.DECRESET(mode)
AssertEQ(self.requestDECMode(mode), [ mode, 2 ])
else:
esccmd.DECRESET(mode)
AssertEQ(self.requestDECMode(mode), [ mode, 2 ])
esccmd.DECSET(mode)
AssertEQ(self.requestDECMode(mode), [ mode, 1 ])
def doPermanentlyResetDecTest(self, mode):
AssertEQ(self.requestDECMode(mode), [ mode, 4 ])
# Modifiable ANSI modes ----------------------------------------------------
@knownBug(terminal="iTerm2", reason="DECRQM not supported.")
def test_DECRQM(self):
"""See if DECRQM works at all. Unlike all the other tests, this one should
never have shouldTry=False set. That way if a terminal with a knownBug
begins supporting DECRQM, this will cease to fail, which is your sign to
remove the 'DECRQM not supported' knownBug from other tests for that
terminal."""
AssertEQ(len(self.requestAnsiMode(esccmd.IRM)), 2)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_KAM(self):
self.doModifiableAnsiTest(esccmd.KAM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_IRM(self):
self.doModifiableAnsiTest(esccmd.IRM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_SRM(self):
self.doModifiableAnsiTest(esccmd.SRM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_LNM(self):
self.doModifiableAnsiTest(esccmd.LNM)
# Permanently reset ANSI modes ----------------------------------------------
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_GATM(self):
self.doPermanentlyResetAnsiTest(esccmd.GATM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_SRTM(self):
self.doPermanentlyResetAnsiTest(esccmd.SRTM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_VEM(self):
self.doPermanentlyResetAnsiTest(esccmd.VEM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_HEM(self):
self.doPermanentlyResetAnsiTest(esccmd.HEM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_PUM(self):
self.doPermanentlyResetAnsiTest(esccmd.PUM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_FEAM(self):
self.doPermanentlyResetAnsiTest(esccmd.FEAM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_FETM(self):
self.doPermanentlyResetAnsiTest(esccmd.FETM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_MATM(self):
self.doPermanentlyResetAnsiTest(esccmd.MATM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_TTM(self):
self.doPermanentlyResetAnsiTest(esccmd.TTM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_SATM(self):
self.doPermanentlyResetAnsiTest(esccmd.SATM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_TSM(self):
self.doPermanentlyResetAnsiTest(esccmd.TSM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_ANSI_EBM(self):
self.doPermanentlyResetAnsiTest(esccmd.EBM)
# Modifiable DEC modes ------------------------------------------------------
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECCKM(self):
self.doModifiableDecTest(esccmd.DECCKM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECCOLM(self):
needsPermission = escargs.args.expected_terminal in [ "xterm", "iTerm2" ]
if needsPermission:
esccmd.DECSET(esccmd.Allow80To132)
self.doModifiableDecTest(esccmd.DECCOLM)
if needsPermission:
esccmd.DECRESET(esccmd.Allow80To132)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECSCLM(self):
self.doModifiableDecTest(esccmd.DECSCLM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECSCNM(self):
self.doModifiableDecTest(esccmd.DECSCNM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECOM(self):
self.doModifiableDecTest(esccmd.DECOM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECAWM(self):
self.doModifiableDecTest(esccmd.DECAWM)
@knownBug(terminal="xterm",
reason="xterm always returns 4 (permanently reset)")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECARM(self):
self.doModifiableDecTest(esccmd.DECARM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECPFF(self):
self.doModifiableDecTest(esccmd.DECPFF)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECPEX(self):
self.doModifiableDecTest(esccmd.DECPEX)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECTCEM(self):
self.doModifiableDecTest(esccmd.DECTCEM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECRLM(self):
self.doModifiableDecTest(esccmd.DECRLM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECHEBM(self):
self.doModifiableDecTest(esccmd.DECHEBM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECHEM(self):
"""Hebrew encoding mode."""
self.doModifiableDecTest(esccmd.DECHEM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECNRCM(self):
self.doModifiableDecTest(esccmd.DECNRCM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECNAKB(self):
self.doModifiableDecTest(esccmd.DECNAKB)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECVCCM(self):
self.doModifiableDecTest(esccmd.DECVCCM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECPCCM(self):
self.doModifiableDecTest(esccmd.DECPCCM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECNKM(self):
self.doModifiableDecTest(esccmd.DECNKM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECBKM(self):
self.doModifiableDecTest(esccmd.DECBKM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECKBUM(self):
self.doModifiableDecTest(esccmd.DECKBUM)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECVSSM(self):
self.doModifiableDecTest(esccmd.DECVSSM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECXRLM(self):
self.doModifiableDecTest(esccmd.DECXRLM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECKPM(self):
self.doModifiableDecTest(esccmd.DECKPM)
@vtLevel(5)
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
@optionRequired(terminal="xterm",
option=escargs.XTERM_WINOPS_ENABLED)
def test_DECRQM_DEC_DECNCSM(self):
needsPermission = escargs.args.expected_terminal in [ "xterm", "iTerm2" ]
if needsPermission:
esccmd.DECSET(esccmd.Allow80To132)
self.doModifiableDecTest(esccmd.DECNCSM)
needsPermission = escargs.args.expected_terminal in [ "xterm", "iTerm2" ]
if needsPermission:
esccmd.DECRESET(esccmd.Allow80To132)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECRLCM(self):
self.doModifiableDecTest(esccmd.DECRLCM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECCRTSM(self):
self.doModifiableDecTest(esccmd.DECCRTSM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECARSM(self):
self.doModifiableDecTest(esccmd.DECARSM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECMCM(self):
self.doModifiableDecTest(esccmd.DECMCM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECAAM(self):
self.doModifiableDecTest(esccmd.DECAAM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECCANSM(self):
self.doModifiableDecTest(esccmd.DECCANSM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECNULM(self):
self.doModifiableDecTest(esccmd.DECNULM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECHDPXM(self):
"""Set duplex."""
self.doModifiableDecTest(esccmd.DECHDPXM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECESKM(self):
self.doModifiableDecTest(esccmd.DECESKM)
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECOSCNM(self):
self.doModifiableDecTest(esccmd.DECOSCNM)
# Permanently Reset DEC Modes -----------------------------------------------
@knownBug(terminal="xterm", reason="Not supported")
@knownBug(terminal="iTerm2", reason="DECRQM not supported.", shouldTry=False)
def test_DECRQM_DEC_DECHCCM(self):
"""Here's what the official docs have to say:
Normally, when you horizontally change the size of your window or
terminal (for example, from 132 columns to 80 columns), the cursor is not
visible. You can change this default by clicking on the Horizontal
Cursor Coupling option.
I also found this on carleton.edu:
Check the Horizontal Cursor Coupling check box if you want the horizontal
scrollbar to be adjusted automatically when the cursor moves to always
keep the column with the cursor on the visible portion of the display.
I gather this is irrelevant if your terminal doesn't support horizontal
scrolling."""
self.doPermanentlyResetDecTest(esccmd.DECHCCM)
from esc import FF, NUL, blank
import escargs
import esccmd
import escio
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug, optionRequired, vtLevel
from esctypes import Point, Rect
class DECRQSSTests(object):
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECRQSS_DECSCA(self):
esccmd.DECSCA(1)
esccmd.DECRQSS('"q')
result = escio.ReadDCS()
AssertEQ(result, '1$r1"q')
@vtLevel(2)
@knownBug(terminal="xterm", reason="DECSCL incorrectly always sets 8 bit controls")
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECRQSS_DECSCL(self):
esccmd.DECSCL(65, 1)
esccmd.DECRQSS('"p')
result = escio.ReadDCS()
AssertEQ(result, '1$r65;1"p')
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECRQSS_DECSTBM(self):
esccmd.DECSTBM(5, 6)
esccmd.DECRQSS("r")
result = escio.ReadDCS()
AssertEQ(result, "1$r5;6r")
@knownBug(terminal="iTerm2", reason="Not implemented.")
def test_DECRQSS_SGR(self):
esccmd.SGR(1)
esccmd.DECRQSS("m")
result = escio.ReadDCS()
AssertEQ(result, "1$r0;1m")
@knownBug(terminal="iTerm2", reason="Not implemented.")
@knownBug(terminal="xterm", reason="DECRQSS always misreports DECSCUSR")
def test_DECRQSS_DECSCUSR(self):
esccmd.DECSCUSR(4)
esccmd.DECRQSS(" q")
result = escio.ReadDCS()
AssertEQ(result, "1$r4 q")
@knownBug(terminal="iTerm2", reason="Not implemented.")
@vtLevel(4)
def test_DECRQSS_DECSLRM(self):
"""Note: not in xcode docs, but supported."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(3, 4)
esccmd.DECRQSS("s")
result = escio.ReadDCS()
AssertEQ(result, "1$r3;4s")
from esc import ESC, NUL
import esccmd
import escio
import esclog
from escutil import AssertEQ, AssertScreenCharsInRectEqual, AssertTrue, GetCursorPosition, GetScreenSize, knownBug, vtLevel
from esctypes import InternalError, Point, Rect
""" level 1, 2, 3, 4
RIS on change
7 vs 8 bit
"""
class DECSCLTests(object):
"""VT Level 1 doesn't have any distinguishing features that are testable that
aren't also in level 2."""
@vtLevel(2)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECSCL")
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECRQM", shouldTry=False)
def test_DECSCL_Level2DoesntSupportDECRQM(self):
"""VT level 2 does not support DECRQM."""
escio.Write("Hello world.")
GetScreenSize()
esccmd.DECSCL(62, 1)
GetScreenSize()
# Make sure DECRQM fails.
try:
esccmd.DECRQM(esccmd.IRM, DEC=False)
escio.ReadCSI('$y')
# Should not get here.
AssertTrue(False)
except InternalError, e:
# Assert something so the test infrastructure is happy.
AssertTrue(True)
@vtLevel(2)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
def test_DSCSCL_Level2Supports7BitControls(self):
esccmd.DECSCL(62, 1)
esccmd.CUP(Point(2, 2))
AssertEQ(GetCursorPosition(), Point(2, 2))
@vtLevel(3)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
@knownBug(terminal="iTerm2", reason="Not implemented", shouldTry=False)
def test_DSCSCL_Level3_SupportsDECRQMDoesntSupportDECSLRM(self):
# Set level 3 conformance
esccmd.DECSCL(63, 1)
# Make sure DECRQM is ok.
esccmd.DECRQM(esccmd.IRM, DEC=False)
escio.ReadCSI('$y')
# Make sure DECSLRM fails.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 6)
esccmd.CUP(Point(5, 1))
escio.Write("abc")
AssertEQ(GetCursorPosition().x(), 8)
@vtLevel(4)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECSCL")
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECNCSM", shouldTry=False)
def test_DECSCL_Level4_SupportsDECSLRMDoesntSupportDECNCSM(self):
# Set level 4 conformance
esccmd.DECSCL(64, 1)
# Enable DECCOLM.
esccmd.DECSET(esccmd.Allow80To132)
# Set DECNCSM, Set column mode. Screen should be cleared anyway.
esccmd.DECRESET(esccmd.DECCOLM)
esccmd.DECSET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("1")
esccmd.DECSET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ NUL ])
# Make sure DECSLRM succeeds.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 6)
esccmd.CUP(Point(5, 1))
escio.Write("abc")
AssertEQ(GetCursorPosition().x(), 6)
@vtLevel(5)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
@knownBug(terminal="iTerm2", reason="Not implemented", shouldTry=False)
def test_DECSCL_Level5_SupportsDECNCSM(self):
# Set level 5 conformance
esccmd.DECSCL(65, 1)
# Set DECNCSM, Set column mode. Screen should not be cleared.
esccmd.DECRESET(esccmd.DECCOLM)
esccmd.DECSET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("1")
esccmd.DECSET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "1" ])
@vtLevel(3)
@knownBug(terminal="xterm", reason="xterm always turns on 8-bit controls.", shouldTry=False)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECSCL")
def test_DECSCL_RISOnChange(self):
"""DECSCL should do an RIS. RIS does a lot, so we'll just test a few
things. This may not be true for VT220's, though, to quote the xterm code:
VT300, VT420, VT520 manuals claim that DECSCL does a
hard reset (RIS). VT220 manual states that it is a soft
reset. Perhaps both are right (unlikely). Kermit says
it's soft.
So that's why this test is for vt level 3 and up."""
escio.Write("x")
# Set saved cursor position
esccmd.CUP(Point(5, 6))
esccmd.DECSC()
# Turn on insert mode
esccmd.SM(esccmd.IRM)
esccmd.DECSCL(61)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ NUL ])
# Ensure saved cursor position is the origin
esccmd.DECRC()
AssertEQ(GetCursorPosition(), Point(1, 1))
# Ensure replace mode is on
esccmd.CUP(Point(1, 1))
escio.Write("a")
esccmd.CUP(Point(1, 1))
escio.Write("b")
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "b" ])
from esc import NUL, blank
import escargs
import esccmd
import escio
from escutil import AssertScreenCharsInRectEqual, knownBug
from esctypes import Point, Rect
class DECSEDTests(object):
def prepare(self):
"""Sets up the display as:
a
bcd
e
With the cursor on the 'c'.
"""
esccmd.CUP(Point(1, 1))
escio.Write("a")
esccmd.CUP(Point(1, 3))
escio.Write("bcd")
esccmd.CUP(Point(1, 5))
escio.Write("e")
esccmd.CUP(Point(2, 3))
def prepare_wide(self):
"""Sets up the display as:
abcde
fghij
klmno
With the cursor on the 'h'.
"""
esccmd.CUP(Point(1, 1))
escio.Write("abcde")
esccmd.CUP(Point(1, 2))
escio.Write("fghij")
esccmd.CUP(Point(1, 3))
escio.Write("klmno")
esccmd.CUP(Point(2, 3))
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_Default(self):
"""Should be the same as DECSED_0."""
self.prepare()
esccmd.DECSED()
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"b" + NUL * 2,
NUL * 3,
NUL * 3 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_0(self):
"""Erase after cursor."""
self.prepare()
esccmd.DECSED(0)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"b" + NUL * 2,
NUL * 3,
NUL * 3 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_1(self):
"""Erase before cursor."""
self.prepare()
esccmd.DECSED(1)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ NUL * 3,
NUL * 3,
blank() * 2 + "d",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_2(self):
"""Erase whole screen."""
self.prepare()
esccmd.DECSED(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ NUL * 3,
NUL * 3,
NUL * 3,
NUL * 3,
NUL * 3 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented", noop=True)
def test_DECSED_3(self):
"""xterm supports a "3" parameter, which also erases scrollback history. There
is no way to test if it's working, though. We can at least test that it doesn't
touch the screen."""
self.prepare()
esccmd.DECSED(3)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_0_WithScrollRegion(self):
"""Erase after cursor with a scroll region present. The scroll region is ignored."""
self.prepare_wide()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(3, 2))
esccmd.DECSED(0)
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ "abcde",
"fg" + NUL * 3,
NUL * 5 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_1_WithScrollRegion(self):
"""Erase before cursor with a scroll region present. The scroll region is ignored."""
self.prepare_wide()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(3, 2))
esccmd.DECSED(1)
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ NUL * 5,
blank() * 3 + "ij",
"klmno" ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_2_WithScrollRegion(self):
"""Erase whole screen with a scroll region present. The scroll region is ignored."""
self.prepare_wide()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(3, 2))
esccmd.DECSED(2)
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ NUL * 5,
NUL * 5,
NUL * 5 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_Default_Protection(self):
"""Should be the same as DECSED_0."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 2,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(2, 5))
escio.Write("X")
esccmd.CUP(Point(2, 3))
esccmd.DECSED()
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_DECSCA_2(self):
"""DECSCA 2 should be the same as DECSCA 0."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 2,1 without protection
esccmd.DECSCA(2)
esccmd.CUP(Point(2, 5))
escio.Write("X")
esccmd.CUP(Point(2, 3))
esccmd.DECSED()
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_0_Protection(self):
"""Erase after cursor."""
esccmd.DECSCA(1)
self.prepare()
# Write this to verify that DECSED is actually doing something.
esccmd.DECSCA(0)
esccmd.CUP(Point(2, 5))
escio.Write("X")
esccmd.CUP(Point(2, 3))
esccmd.DECSED(0)
# X should be erased, other characters not.
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_1_Protection(self):
"""Erase before cursor."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 2,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(2, 1))
escio.Write("X")
esccmd.CUP(Point(2, 3))
esccmd.DECSED(1)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_2_Protection(self):
"""Erase whole screen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 2,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(2, 1))
escio.Write("X")
# Erase the screen
esccmd.DECSED(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "a" + NUL * 2,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented", noop=True)
def test_DECSED_3_Protection(self):
"""xterm supports a "3" parameter, which also erases scrollback history. There
is no way to test if it's working, though. We can at least test that it doesn't
touch the screen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 2,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(2, 1))
escio.Write("X")
esccmd.DECSED(3)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 5),
[ "aX" + NUL,
NUL * 3,
"bcd",
NUL * 3,
"e" + NUL * 2 ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_0_WithScrollRegion_Protection(self):
"""Erase after cursor with a scroll region present. The scroll region is ignored."""
esccmd.DECSCA(1)
self.prepare_wide()
# Write an X at 1,3 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 3))
escio.Write("X")
# Set up margins
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
# Position cursor in margins and do DECSED 0
esccmd.CUP(Point(3, 2))
esccmd.DECSED(0)
# Remove margins to compute checksum
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ "abcde",
"fghij",
blank() + "lmno" ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_1_WithScrollRegion_Protection(self):
"""Erase after cursor with a scroll region present. The scroll region is ignored."""
esccmd.DECSCA(1)
self.prepare_wide()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
escio.Write("X")
# Set margins
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
# Position cursor and do DECSED 1
esccmd.CUP(Point(3, 2))
esccmd.DECSED(1)
# Remove margins
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ blank() + "bcde",
"fghij",
"klmno" ])
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_2_WithScrollRegion_Protection(self):
"""Erase whole screen with a scroll region present. The scroll region is ignored."""
esccmd.DECSCA(1)
self.prepare_wide()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(3, 2))
esccmd.DECSED(2)
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 3),
[ blank() + "bcde",
"fghij",
"klmno" ])
@knownBug(terminal="xterm",
reason="DECSED respects ISO protection for backward compatibility reasons, per email from Thomas")
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSED_doesNotRespectISOProtect(self):
"""DECSED does not respect ISO protection."""
escio.Write("a")
esccmd.SPA()
escio.Write("b")
esccmd.EPA()
esccmd.DECSED(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 2, 1), [ blank() * 2 ])
from esc import NUL, blank
import escargs
import esccmd
import escio
from esctypes import Point, Rect
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, knownBug
class DECSELTests(object):
def prepare(self):
"""Initializes the screen to abcdefghij on the first line with the cursor
on the 'e'."""
esccmd.CUP(Point(1, 1))
escio.Write("abcdefghij")
esccmd.CUP(Point(5, 1))
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_Default(self):
"""Should erase to right of cursor."""
self.prepare()
esccmd.DECSEL()
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ "abcd" + 6 * NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_0(self):
"""Should erase to right of cursor."""
self.prepare()
esccmd.DECSEL(0)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ "abcd" + 6 * NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_1(self):
"""Should erase to left of cursor."""
self.prepare()
esccmd.DECSEL(1)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ 5 * blank() + "fghij" ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_2(self):
"""Should erase whole line."""
self.prepare()
esccmd.DECSEL(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ 10 * NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_IgnoresScrollRegion(self):
"""Should erase whole line."""
self.prepare()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(5, 1))
esccmd.DECSEL(2)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ 10 * NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_Default_Protection(self):
"""Should erase to right of cursor."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(10, 1))
escio.Write("X")
esccmd.CUP(Point(5, 1))
esccmd.DECSEL()
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ "abcdefghi" + NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_0_Protection(self):
"""All letters are protected so nothing should happen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(10, 1))
escio.Write("X")
esccmd.CUP(Point(5, 1))
esccmd.DECSEL(0)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ "abcdefghi" + NUL ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_1_Protection(self):
"""All letters are protected so nothing should happen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.CUP(Point(5, 1))
esccmd.DECSEL(1)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ blank() + "bcdefghij" ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_2_Protection(self):
"""All letters are protected so nothing should happen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.DECSEL(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ blank() + "bcdefghij" ])
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_DECSEL_IgnoresScrollRegion_Protection(self):
"""All letters are protected so nothing should happen."""
esccmd.DECSCA(1)
self.prepare()
# Write an X at 1,1 without protection
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(5, 1))
esccmd.DECSEL(2)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 10, 1),
[ blank() + "bcdefghij" ])
@knownBug(terminal="xterm",
reason="DECSEL respects ISO protection for backward compatibility reasons, per email from Thomas")
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSEL_doesNotRespectISOProtect(self):
"""DECSEL does not respect ISO protection."""
escio.Write("a")
esccmd.SPA()
escio.Write("b")
esccmd.EPA()
esccmd.DECSEL(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 2, 1), [ blank() * 2 ])
import tests.fill_rectangle
import esc
import esccmd
import escio
from escutil import AssertScreenCharsInRectEqual, Point, Rect, knownBug
class DECSERATests(tests.fill_rectangle.FillRectangleTests):
def __init__(self):
tests.fill_rectangle.FillRectangleTests.__init__(self)
self._always_return_blank = False
def prepare(self):
esccmd.CUP(Point(1, 1))
i = 1
for line in self.data():
# Protect odd-numbered rows
esccmd.DECSCA(i)
escio.Write(line + esc.CR + esc.LF)
i = 1 - i
esccmd.DECSCA(0)
def fill(self, top=None, left=None, bottom=None, right=None):
esccmd.DECSERA(top, left, bottom, right)
def characters(self, point, count):
if self._always_return_blank:
return esc.blank() * count
s = ""
data = self.data()
for i in xrange(count):
p = Point(point.x() + i, point.y())
if p.y() >= len(data):
s += esc.blank()
continue
line = data[p.y() - 1]
if p.x() >= len(line):
s += esc.blank()
continue
if point.y() % 2 == 1:
s += line[p.x() - 1]
else:
s += esc.blank()
return s
def test_DECSERA_basic(self):
self.fillRectangle_basic()
def test_DECSERA_invalidRectDoesNothing(self):
self.fillRectangle_invalidRectDoesNothing()
@knownBug(terminal="xterm",
reason="xterm doesn't accept all default params for DECSERA, although it does work if there is a single semicolon")
def test_DECSERA_defaultArgs(self):
try:
self._always_return_blank = True
self.fillRectangle_defaultArgs()
finally:
self._always_return_blank = False
def test_DECSERA_respectsOriginMode(self):
self.fillRectangle_respectsOriginMode()
def test_DECSERA_overlyLargeSourceClippedToScreenSize(self):
self.fillRectangle_overlyLargeSourceClippedToScreenSize()
def test_DECSERA_cursorDoesNotMove(self):
self.fillRectangle_cursorDoesNotMove()
def test_DECSERA_ignoresMargins(self):
self.fillRectangle_ignoresMargins()
@knownBug(terminal="iTerm2", reason="DECSED not implemented")
def test_DECSERA_doesNotRespectISOProtect(self):
"""DECSERA does not respect ISO protection."""
escio.Write("a")
esccmd.SPA()
escio.Write("b")
esccmd.EPA()
esccmd.DECSERA(1, 1, 1, 2)
AssertScreenCharsInRectEqual(Rect(1, 1, 2, 1), [ esc.blank() * 2 ])
from esc import ESC, TAB, NUL, CR, LF, BS
from esctypes import Point, Rect
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug, optionRequired, vtLevel, optionRejects
import escargs
import esccmd
import escio
import esclog
import time
# Note: There is no test for DECRESET; that is handled here.
# Can't test the following:
# DECCKM - requires user action at the keyboard
# DECSCLM - affects visual presentation of scrolling only
# DECSCNM - changes color palette
# DECARM - requires user action at the keyboard
# Mouse Tracking (9) - requires user action at mouse
# Show Toolbar (10) - no way to introspect toolbar
# Start Blinking Cursor (12) - no way to introspect cursor status
# DECPFF - no way to examine output to printer
# DECPEX - no way to examine output to printer
# DECTCEM - no way to tell if the cursor is visible
# Show Scrollbar (30) - no way to tell if scroll bar is visible
# Enable font-shifting (35) - I think this enables/disables a keyboard shortcut to grow or shrink the font. Not testable because user interaction is required.
# DECTEK - Tektronix is out of scope for now (and probably not introspectable, I guess).
# DECNRCM - Can't introspect character sets
# Margin Bell (44) - Can't tell if bell is ringing
# Allow Logging (46) - Not on by default
# DECNKM - Requires user interaction to detect app keypad
# DECBKM - Requires user interaction to see what back arrow key sends
# Mouse tracking (1000, 1001, 1002, 1003, 1005, 1006, 1007, 1015) - Requires user interaction with mouse
# Focus In/Out (1004) - Requires user interaction
# Scroll to bottom on tty output (1010) - Can't introspect scroll position
# Scroll to bottom on tty output (1011) - Can't introspect scroll position and requires user interaction with keyboard
# Interpret meta key sets 8th bit - Requires user interaction with keyboard
# Enable special modifiers for Alt and NumLock keys - Requires user interaction with keyboard
# Send ESC when Meta modifies a key - Requires user interaction with keyboard
# Send DEL from the editing-keypad Delete key - Requires user interaction with keyboard
# Send ESC when Alt modifies a key - Requires user interaction with keyboard
# Keep selection even if not highlighted - Can't set selection
# Use the CLIPBOARD selection - Can't set selection
# Enable Urgency window manager hint when Control-G is received - Can't introspect window manager
# Enable raising of the window when Control-G is received - Can't introspect window raised status
# Set terminfo/termcap function-key mode - Requires user interaction.
# Set Sun function-key mode - Requires user interaction.
# Set HP function-key mode - Requires user interaction.
# Set SCO function-key mode - Requires user interaction.
# Set legacy keyboard emulation (X11R6) - Requires user interaction.
# Set VT220 keyboard emulation - Requires user interaction.
# Set bracketed paste mode - Requires user interaction.
# TODO: test DECANM. It sets the font to USASCII and sets VT100 mode
class DECSETTests(object):
def test_DECSET_DECCOLM(self):
"""Set 132 column mode."""
# From the docs:
# When the terminal receives the sequence, the screen is erased and the
# cursor moves to the home position. This also sets the scrolling region
# for full screen
# Enable DECCOLM.
esccmd.DECSET(esccmd.Allow80To132)
# Write something to verify that it gets erased
esccmd.CUP(Point(5, 5))
escio.Write("x")
# Set left-right and top-bottom margins to ensure they're removed.
esccmd.DECSTBM(1, 2)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(1, 2)
# Enter 132-column mode.
esccmd.DECSET(esccmd.DECCOLM)
# Check that the screen got resized
AssertEQ(GetScreenSize().width(), 132)
# Make sure the cursor is at the origin
position = GetCursorPosition()
AssertEQ(position.x(), 1)
AssertEQ(position.y(), 1)
# Write to make sure the scroll regions are gone
escio.Write(CR + LF)
escio.Write("Hello")
escio.Write(CR + LF)
escio.Write("World")
esccmd.DECSTBM()
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 2, 5, 3), [ "Hello", "World" ])
AssertScreenCharsInRectEqual(Rect(5, 5, 5, 5), [ NUL ])
@knownBug(terminal="iTerm2", reason="iTerm2 has an off-by-one bug with origin mode.")
def test_DECSET_DECOM(self):
"""Set origin mode. Cursor positioning is relative to the scroll region's
top left."""
# Origin mode allows cursor addressing relative to a user-defined origin.
# This mode resets when the terminal is powered up or reset. It does not
# affect the erase in display (ED) function.
esccmd.DECSTBM(5, 7)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 7)
esccmd.DECSET(esccmd.DECOM)
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(5, 5, 5, 5), [ "X" ])
def test_DECSET_DECOM_SoftReset(self):
"""Soft reset turns off DECOM."""
esccmd.DECSTBM(5, 7)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 7)
esccmd.DECSET(esccmd.DECOM)
esccmd.DECSTR()
esccmd.CHA(1)
esccmd.VPA(1)
escio.Write("X")
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "X" ])
@knownBug(terminal="iTerm2", reason="DECRQCRA does not respect origin mode in iTerm2")
def test_DECSET_DECOM_DECRQCRA(self):
"""DECRQCRA should be relative to the origin in origin mode. DECRQCRA
doesn't have its own test so this is tested here instead."""
esccmd.CUP(Point(5, 5))
escio.Write("X")
esccmd.DECSTBM(5, 7)
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 7)
esccmd.DECSET(esccmd.DECOM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "X" ])
# This test is flaky so I turned off shouldTry to avoid false failures.
@knownBug(terminal="xterm",
reason="xterm produces incorrect output if ABC is written too quickly. A pause before writing the C produces correct output.",
shouldTry=False)
def test_DECSET_DECAWM(self):
"""Auto-wrap mode."""
size = GetScreenSize()
esccmd.CUP(Point(size.width() - 1, 1))
esccmd.DECSET(esccmd.DECAWM)
escio.Write("abc")
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 2), [ "c" ])
esccmd.CUP(Point(size.width() - 1, 1))
esccmd.DECRESET(esccmd.DECAWM)
escio.Write("ABC")
AssertScreenCharsInRectEqual(Rect(size.width() - 1, 1, size.width(), 1), [ "AC" ])
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 2), [ "c" ])
def test_DECSET_DECAWM_CursorAtRightMargin(self):
"""If you start at column 1 and write N+1 characters (where N is the width of
the window) the cursor's position should go: 1, 2, ..., N, N, 2."""
esccmd.DECSET(esccmd.DECAWM)
size = GetScreenSize()
# 1, 2, ... N - 2
AssertEQ(GetCursorPosition().x(), 1)
for i in xrange(size.width() - 2):
escio.Write("x")
AssertEQ(GetCursorPosition().x(), size.width() - 1)
# Write the N-1th character, cursor enters the right margin.
escio.Write("x")
AssertEQ(GetCursorPosition().x(), size.width())
# Nth: cursor still at right margin!
escio.Write("x")
AssertEQ(GetCursorPosition().x(), size.width())
# N+1th: cursor wraps around to second position.
escio.Write("x")
AssertEQ(GetCursorPosition().x(), 2)
# xterm doesn't implement auto-wrap mode when wide characters are disabled.
@optionRejects(terminal="xterm", option=escargs.DISABLE_WIDE_CHARS)
def test_DECSET_DECAWM_OnRespectsLeftRightMargin(self):
"""Auto-wrap mode on respects left-right margins."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 9)
esccmd.DECSTBM(5, 9)
esccmd.CUP(Point(8, 9))
esccmd.DECSET(esccmd.DECAWM)
escio.Write("abcdef")
AssertScreenCharsInRectEqual(Rect(5, 8, 9, 9), [ NUL * 3 + "ab", "cdef" + NUL ])
@knownBug(terminal="iTerm2",
reason="Upon reaching the right margin, iTerm2 incorrectly moves the cursor to the right edge of the screen.")
def test_DECSET_DECAWM_OffRespectsLeftRightMargin(self):
"""Auto-wrap mode off respects left-right margins."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 9)
esccmd.DECSTBM(5, 9)
esccmd.CUP(Point(8, 9))
esccmd.DECRESET(esccmd.DECAWM)
escio.Write("abcdef")
AssertEQ(GetCursorPosition().x(), 9)
AssertScreenCharsInRectEqual(Rect(5, 8, 9, 9), [ NUL * 5, NUL * 3 + "af" ])
def test_DECSET_Allow80To132(self):
"""DECCOLM only has an effect if Allow80To132 is on."""
# There are four tests:
# Allowed Not allowed
# 80->132 1 3
# 132->80 2 4
# Test 1: 80->132, allowed
# Allow 80 to 132.
esccmd.DECSET(esccmd.Allow80To132)
if (GetScreenSize().width() == 132):
# Enter 80 columns so the test can proceed.
esccmd.DECRESET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 80)
# Enter 132
esccmd.DECSET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 132)
# Test 2: 132->80, allowed
esccmd.DECRESET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 80)
# Test 3: 80->132
# Disallow 80 to 132
esccmd.DECRESET(esccmd.Allow80To132)
# Try to enter 132 - should do nothing.
esccmd.DECSET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 80)
# Allow 80 to 132
esccmd.DECSET(esccmd.Allow80To132)
# Enter 132
esccmd.DECSET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 132)
# Disallow 80 to 132
esccmd.DECRESET(esccmd.Allow80To132)
# Try to enter 80 - should do nothing.
esccmd.DECRESET(esccmd.DECCOLM)
AssertEQ(GetScreenSize().width(), 132)
def fillLineAndWriteTab(self):
escio.Write(CR + LF)
size = GetScreenSize()
for i in xrange(size.width()):
escio.Write("x")
escio.Write(TAB)
@knownBug(terminal="iTerm2", reason="iTerm2 wraps tabs")
def test_DECSET_DECAWM_TabDoesNotWrapAround(self):
"""In auto-wrap mode, tabs to not wrap to the next line."""
esccmd.DECSET(esccmd.DECAWM)
size = GetScreenSize()
for i in xrange(size.width() / 8 + 2):
escio.Write(TAB)
AssertEQ(GetCursorPosition().x(), size.width())
AssertEQ(GetCursorPosition().y(), 1)
@knownBug(terminal="iTerm2", reason="iTerm2 doesn't implement DECSET 41 (MoreFix).")
def test_DECSET_MoreFix(self):
"""xterm supports DECSET 41 to enable a fix for a bug in curses where it
would draw to the end of a row and then insert a tab. When 41 is set, the
tab is drawn."""
# With MoreFix on, test that writing N x'es followed by a tab leaves the
# cursor at the first tab stop.
esccmd.DECSET(esccmd.MoreFix)
self.fillLineAndWriteTab()
AssertEQ(GetCursorPosition().x(), 9)
escio.Write("1")
AssertScreenCharsInRectEqual(Rect(9, 3, 9, 3), [ "1" ])
# With MoreFix off, test that writing N x'es followed by a tab leaves the cursor at
# the right margin
esccmd.DECRESET(esccmd.MoreFix)
self.fillLineAndWriteTab()
AssertEQ(GetCursorPosition().x(), GetScreenSize().width())
escio.Write("2")
AssertScreenCharsInRectEqual(Rect(1, 5, 1, 5), [ "2" ])
@knownBug(terminal="iTerm2",
reason="iTerm2 only reverse wraps-around if there's a soft newline at the preceding line.")
def test_DECSET_ReverseWraparound_BS(self):
"""xerm supports DECSET 45 to toggle 'reverse wraparound'. Both DECAWM and
45 must be set."""
# iTerm2 turns reverse wraparound on by default, while xterm does not.
esccmd.DECSET(esccmd.ReverseWraparound)
esccmd.DECSET(esccmd.DECAWM)
esccmd.CUP(Point(1, 2))
escio.Write(BS)
AssertEQ(GetCursorPosition().x(), GetScreenSize().width())
@knownBug(terminal="iTerm2", reason="iTerm2 moves the cursor back an extra space.")
def test_DECSET_ReverseWraparoundLastCol_BS(self):
"""If the cursor is in the last column and a character was just output and
reverse-wraparound is on then backspace by 1 has no effect."""
esccmd.DECSET(esccmd.ReverseWraparound)
esccmd.DECSET(esccmd.DECAWM)
size = GetScreenSize()
esccmd.CUP(Point(size.width() - 1, 1))
escio.Write("a")
AssertEQ(GetCursorPosition().x(), size.width())
escio.Write("b")
AssertEQ(GetCursorPosition().x(), size.width())
escio.Write(BS)
AssertEQ(GetCursorPosition().x(), size.width())
def test_DECSET_ReverseWraparound_Multi(self):
size = GetScreenSize()
esccmd.CUP(Point(size.width() - 1, 1))
escio.Write("abcd")
esccmd.DECSET(esccmd.ReverseWraparound)
esccmd.DECSET(esccmd.DECAWM)
esccmd.CUB(4)
AssertEQ(GetCursorPosition().x(), size.width() - 1)
@knownBug(terminal="iTerm2",
reason="iTerm2 doesn't implement DECRESET ReverseWraparound.")
def test_DECSET_ResetReverseWraparoundDisablesIt(self):
"""DECRESET of reverse wraparound prevents it from happening."""
# iTerm2 turns reverse wraparound on by default, while xterm does not.
esccmd.DECRESET(esccmd.ReverseWraparound)
esccmd.DECSET(esccmd.DECAWM)
esccmd.CUP(Point(GetScreenSize().width() - 1, 1))
escio.Write("abc")
escio.Write(BS * 5)
AssertEQ(GetCursorPosition().x(), 1)
@knownBug(terminal="iTerm2",
reason="iTerm2 does not require DECAWM for reverse wrap.")
def test_DECSET_ReverseWraparound_RequiresDECAWM(self):
"""Reverse wraparound only works if DECAWM is set."""
# iTerm2 turns reverse wraparound on by default, while xterm does not.
esccmd.CUP(Point(GetScreenSize().width() - 1, 1))
escio.Write("abc")
esccmd.DECSET(esccmd.ReverseWraparound)
esccmd.DECRESET(esccmd.DECAWM)
escio.Write(BS * 5)
AssertEQ(GetCursorPosition().x(), 1)
def doAltBuftest(self, code, altGetsClearedBeforeToMain, cursorSaved):
"""|code| is the code to test with, either 47 or 1047."""
# Scribble in main screen
escio.Write("abc" + CR + LF + "abc")
# Switch from main to alt. Cursor should not move. If |cursorSaved| is set,
# record the position first to verify that it's restored after DECRESET.
if cursorSaved:
mainCursorPosition = GetCursorPosition()
before = GetCursorPosition()
esccmd.DECSET(code)
after = GetCursorPosition()
AssertEQ(before.x(), after.x())
AssertEQ(before.y(), after.y())
# Scribble in alt screen, clearing it first since who knows what might have
# been there.
esccmd.ED(2)
esccmd.CUP(Point(1, 2))
escio.Write("def" + CR +LF + "def")
# Make sure abc is gone
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 3), [ NUL * 3, "def", "def" ])
# Switch to main. Cursor should not move.
before = GetCursorPosition()
esccmd.DECRESET(code)
after = GetCursorPosition()
if cursorSaved:
AssertEQ(mainCursorPosition.x(), after.x())
AssertEQ(mainCursorPosition.y(), after.y())
else:
AssertEQ(before.x(), after.x())
AssertEQ(before.y(), after.y())
# def should be gone, abc should be back.
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 3), [ "abc", "abc", NUL * 3 ])
# Switch to alt
before = GetCursorPosition()
esccmd.DECSET(code)
after = GetCursorPosition()
AssertEQ(before.x(), after.x())
AssertEQ(before.y(), after.y())
if altGetsClearedBeforeToMain:
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 3), [ NUL * 3, NUL * 3, NUL * 3 ])
else:
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 3), [ NUL * 3, "def", "def" ])
@knownBug(terminal="iTerm2", reason="DECSET 1047 (OPT_ALTBUF) not implemented.")
def test_DECSET_OPT_ALTBUF(self):
"""DECSET 47 and DECSET 1047 do the same thing: If not in alt screen,
switch to it. Its contents are NOT erased.
DECRESET 1047 If on alt screen, clear the alt screen and then switch to the
main screen."""
self.doAltBuftest(esccmd.OPT_ALTBUF, True, False)
def test_DECSET_ALTBUF(self):
"""DECSET 47 and DECSET 1047 do the same thing: If not in alt screen,
switch to it. Its contents are NOT erased.
DECRESET 47 switches to the main screen (without first clearing the alt
screen)."""
self.doAltBuftest(esccmd.ALTBUF, False, False)
def test_DECSET_OPT_ALTBUF_CURSOR(self):
"""DECSET 1049 is like 1047 but it also saves the cursor position before
entering alt and restores it after returning to main."""
self.doAltBuftest(esccmd.OPT_ALTBUF_CURSOR, True, True)
# xterm doesn't implement auto-wrap mode when wide characters are disabled.
@optionRejects(terminal="xterm", option=escargs.DISABLE_WIDE_CHARS)
def test_DECSET_DECLRMM(self):
"""Left-right margin. This is tested extensively in many other places as well."""
# Turn on margins and write.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
escio.Write("abcdefgh")
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 4, 3), [ "abcd", NUL + "efg", NUL + "h" + NUL * 2 ])
# Turn off margins.
esccmd.CUP(Point(1, 1))
escio.Write("ABCDEFGH")
AssertScreenCharsInRectEqual(Rect(1, 1, 8, 1), [ "ABCDEFGH" ])
@knownBug(terminal="iTerm2",
reason="iTerm2 fails to reset DECLRMM (it just sets the margins to the screen edges)")
def test_DECSET_DECLRMM_ResetByDECSTR(self):
"""DECSTR should turn off DECLRMM."""
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSTR()
esccmd.DECSET(esccmd.DECAWM)
esccmd.DECSET(esccmd.ReverseWraparound)
esccmd.CUP(Point(GetScreenSize().width() - 1, 1))
escio.Write("abc")
# Reverse wraparound is disabled (at least in iTerm2) when a scroll region is present.
escio.Write(BS * 3)
AssertEQ(GetCursorPosition().y(), 1)
@vtLevel(5)
@knownBug(terminal="iTerm2", reason="DECNCSM not implemented")
@optionRequired(terminal="xterm",
option=escargs.XTERM_WINOPS_ENABLED)
def test_DECSET_DECNCSM(self):
"""From the manual: When enabled, a column mode change (either through
Set-Up or by the escape sequence DECCOLM) does not clear the screen. When
disabled, the column mode change clears the screen as a side effect."""
# There are four tests:
# DECNCSM Set DECNCSM Reset
# Column Mode Set 1 3
# Column Mode Reset 2 4
# 1: Set DECNCSM, Set column mode.
esccmd.DECRESET(esccmd.DECCOLM)
esccmd.DECSET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("1")
esccmd.DECSET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "1" ])
# 2: Set DECNCSM, Reset column mode.
esccmd.DECSET(esccmd.DECCOLM)
esccmd.DECSET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("2")
esccmd.DECRESET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "2" ])
# 3: Reset DECNCSM, Set column mode.
esccmd.DECRESET(esccmd.DECCOLM)
esccmd.DECRESET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("3")
esccmd.DECSET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ NUL ])
# 4: Reset DECNCSM, Reset column mode.
esccmd.DECSET(esccmd.DECCOLM)
esccmd.DECRESET(esccmd.DECNCSM)
esccmd.CUP(Point(1, 1))
escio.Write("4")
esccmd.DECRESET(esccmd.DECCOLM)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ NUL ])
@knownBug(terminal="iTerm2", reason="Save/restore cursor not implemented")
def test_DECSET_SaveRestoreCursor(self):
"""Set saves the cursor position. Reset restores it."""
esccmd.CUP(Point(2, 3))
esccmd.DECSET(esccmd.SaveRestoreCursor)
esccmd.CUP(Point(5, 5))
esccmd.DECRESET(esccmd.SaveRestoreCursor)
cursor = GetCursorPosition()
AssertEQ(cursor.x(), 2)
AssertEQ(cursor.y(), 3)
from tests.save_restore_cursor import SaveRestoreCursorTests
import esccmd
from escutil import knownBug
class DECSETTiteInhibitTests(SaveRestoreCursorTests):
def __init__(self):
SaveRestoreCursorTests.__init__(self)
def saveCursor(self):
esccmd.DECSET(esccmd.SaveRestoreCursor)
def restoreCursor(self):
esccmd.DECRESET(esccmd.SaveRestoreCursor)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_SaveRestoreCursor_Basic(self):
SaveRestoreCursorTests.test_SaveRestoreCursor_Basic(self)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_SaveRestoreCursor_MoveToHomeWhenNotSaved(self):
SaveRestoreCursorTests.test_SaveRestoreCursor_MoveToHomeWhenNotSaved(self)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_SaveRestoreCursor_ResetsOriginMode(self):
SaveRestoreCursorTests.test_SaveRestoreCursor_ResetsOriginMode(self)
@knownBug(terminal="iTerm2", reason="Not implemented")
def test_SaveRestoreCursor_WorksInLRM(self, shouldWork=True):
SaveRestoreCursorTests.test_SaveRestoreCursor_WorksInLRM(self)
from esc import CR, LF, NUL
import esccmd
import escio
from escutil import AssertEQ, GetCursorPosition, GetScreenSize, AssertScreenCharsInRectEqual, knownBug
from esctypes import Point, Rect
class DECSTBMTests(object):
"""DECSTBM is tested pretty well in various other tests; this is meant to
cover the basics."""
def test_DECSTBM_ScrollsOnNewline(self):
"""Define a top-bottom margin, put text in it, and have newline scroll it."""
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(1, 2))
escio.Write("1" + CR + LF)
escio.Write("2")
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "1", "2" ])
escio.Write(CR + LF)
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "2", NUL ])
AssertEQ(GetCursorPosition().y(), 3)
def test_DECSTBM_NewlineBelowRegion(self):
"""A newline below the region has no effect on the region."""
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(1, 2))
escio.Write("1" + CR + LF)
escio.Write("2")
esccmd.CUP(Point(1, 4))
escio.Write(CR + LF)
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "1", "2" ])
def test_DECSTBM_MovsCursorToOrigin(self):
"""DECSTBM moves the cursor to column 1, line 1 of the page."""
esccmd.CUP(Point(3, 2))
esccmd.DECSTBM(2, 3)
AssertEQ(GetCursorPosition(), Point(1, 1))
@knownBug(terminal="iTerm2",
reason="iTerm2 sets a scroll region but should not.")
def test_DECSTBM_TopBelowBottom(self):
"""The value of the top margin (Pt) must be less than the bottom margin (Pb)."""
size = GetScreenSize()
esccmd.DECSTBM(3, 3)
for i in xrange(size.height()):
escio.Write("%04d" % i)
y = i + 1
if y != size.height():
escio.Write(CR + LF)
for i in xrange(size.height()):
y = i + 1
AssertScreenCharsInRectEqual(Rect(1, y, 4, y), [ "%04d" % i ])
esccmd.CUP(Point(1, size.height()))
escio.Write(LF)
for i in xrange(size.height() - 1):
y = i + 1
AssertScreenCharsInRectEqual(Rect(1, y, 4, y), [ "%04d" % (i + 1) ])
y = size.height()
AssertScreenCharsInRectEqual(Rect(1, y, 4, y), [ NUL * 4 ])
def test_DECSTBM_DefaultRestores(self):
"""Default args restore to full screen scrolling."""
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(1, 2))
escio.Write("1" + CR + LF)
escio.Write("2")
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "1", "2" ])
position = GetCursorPosition()
esccmd.DECSTBM()
esccmd.CUP(position)
escio.Write(CR + LF)
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "1", "2" ])
AssertEQ(GetCursorPosition().y(), 4)
@knownBug(terminal="iTerm2",
reason="iTerm2 incorretly scrolls the whole screen when there's a bottom margin above the bottom of the page, the cursor is at the bottom of the page, and a LF is received. No scrolling should occur outside the margins.")
def test_DECSTBM_CursorBelowRegionAtBottomTriesToScroll(self):
"""You cannot perform scrolling outside the margins."""
esccmd.DECSTBM(2, 3)
esccmd.CUP(Point(1, 2))
escio.Write("1" + CR + LF)
escio.Write("2")
size = GetScreenSize()
esccmd.CUP(Point(1, size.height()))
escio.Write("3" + CR + LF)
AssertScreenCharsInRectEqual(Rect(1, 2, 1, 3), [ "1", "2" ])
AssertScreenCharsInRectEqual(Rect(1, size.height(), 1, size.height()), [ "3" ])
AssertEQ(GetCursorPosition().y(), size.height())
def test_DECSTBM_MaxSizeOfRegionIsPageSize(self):
"""The maximum size of the scrolling region is the page size."""
# Write "x" at line 2
esccmd.CUP(Point(1, 2))
escio.Write("x")
# Set the scroll bottom to below the screen.
size = GetScreenSize()
esccmd.DECSTBM(1, GetScreenSize().height() + 10)
# Move the cursor to the last line and write a newline.
esccmd.CUP(Point(1, size.height()))
escio.Write(CR + LF)
# Verify that line 2 scrolled up to line 1.
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 2), [ "x", NUL ])
# Verify the cursor is at the last line on the page.
AssertEQ(GetCursorPosition().y(), size.height())
from esc import BS, CR, ESC, LF, NUL
import esccmd
import escio
import esclog
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, intentionalDeviationFromSpec, knownBug
from esctypes import Point, Rect
class DECSTRTests(object):
"""The following settings are reset:
DECTCEM Cursor enabled.
IRM Replace mode.
DECOM Absolute (cursor origin at upper-left of screen.)
DECAWM No autowrap.
DECNRCM Multinational set.
KAM Unlocked.
DECNKM Numeric characters.
DECCKM Normal (arrow keys).
DECSTBM Top margin = 1; bottom margin = page length.
G0, G1, G2, G3, GL, GR Default settings.
SGR Normal rendition.
DECSCA Normal (erasable by DECSEL and DECSED).
DECSC Home position.
DECAUPSS Set selected in Set-Up.
DECSASD Main display.
DECKPM Character codes.
DECRLM Reset (Left-to-right), regardless of NVR setting.
DECPCTERM Always reset."""
@knownBug(terminal="iTerm2", reason="iTerm2 fails to reset saved cursor position.")
def test_DECSTR_DECSC(self):
# Save cursor position
esccmd.CUP(Point(5, 6))
esccmd.DECSC()
# Perform soft reset
esccmd.DECSTR()
# Ensure saved cursor position is the origin
esccmd.DECRC()
AssertEQ(GetCursorPosition(), Point(1, 1))
def test_DECSTR_IRM(self):
# Turn on insert mode
esccmd.SM(esccmd.IRM)
# Perform soft reset
esccmd.DECSTR()
# Ensure replace mode is on
esccmd.CUP(Point(1, 1))
escio.Write("a")
esccmd.CUP(Point(1, 1))
escio.Write("b")
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "b" ])
def test_DECSTR_DECOM(self):
# Define a scroll region
esccmd.DECSTBM(3, 4)
# Turn on origin mode
esccmd.DECSET(esccmd.DECOM)
# Perform soft reset
esccmd.DECSTR()
# Define scroll region again
esccmd.DECSTBM(3, 4)
# Move to 1,1 (or 3,4 if origin mode is still on) and write an X
esccmd.CUP(Point(1, 1))
escio.Write("X")
# Turn off origin mode
esccmd.DECRESET(esccmd.DECOM)
# Make sure the X was at 1, 1, implying origin mode was off.
esccmd.DECSTBM()
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "X" ])
@intentionalDeviationFromSpec(terminal="iTerm2",
reason="For compatibility purposes, iTerm2 mimics xterm's behavior of turning on DECAWM by default.")
@intentionalDeviationFromSpec(terminal="iTerm2",
reason="For compatibility purposes, xterm turns on DECAWM by default.")
def test_DECSTR_DECAWM(self):
# Turn on autowrap
esccmd.DECSET(esccmd.DECAWM)
# Perform soft reset
esccmd.DECSTR()
# Make sure autowrap is still on
esccmd.CUP(Point(GetScreenSize().width() - 1, 1))
escio.Write("xxx")
position = GetCursorPosition()
AssertEQ(position.x(), 2)
@knownBug(terminal="iTerm2", reason="Reverse wrap is always on in iTerm2")
def test_DECSTR_ReverseWraparound(self):
# Turn on reverse wraparound
esccmd.DECSET(esccmd.ReverseWraparound)
# Perform soft reset
esccmd.DECSTR()
# Verify reverse wrap is off
esccmd.CUP(Point(GetScreenSize().width() - 1, 2))
escio.Write("abc" + BS * 3)
AssertEQ(GetCursorPosition().x(), 1)
def test_DECSTR_STBM(self):
# Set top and bottom margins
esccmd.DECSTBM(3, 4)
# Perform soft reset
esccmd.DECSTR()
# Ensure no margins
esccmd.CUP(Point(1, 4))
escio.Write(CR + LF)
AssertEQ(GetCursorPosition().y(), 5)
@knownBug(terminal="iTerm2", reason="DECSCA not implemented")
def test_DECSTR_DECSCA(self):
# Turn on character protection
esccmd.DECSCA(1)
# Perform soft reset
esccmd.DECSTR()
# Ensure character protection is off
esccmd.CUP(Point(1, 1))
escio.Write("X")
esccmd.DECSED(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ NUL ])
def test_DECSTR_DECSASD(self):
# Direct output to status line
esccmd.DECSASD(1)
# Perform soft reset
esccmd.DECSTR()
# Ensure output goes to screen
escio.Write("X")
AssertScreenCharsInRectEqual(Rect(1, 1, 1, 1), [ "X" ])
def test_DECSTR_DECRLM(self):
# Set right-to-left mode
esccmd.DECSET(esccmd.DECRLM)
# Perform soft reset
esccmd.DECSTR()
# Ensure text goes left to right
esccmd.CUP(Point(2, 1))
escio.Write("a")
escio.Write("b")
AssertScreenCharsInRectEqual(Rect(2, 1, 2, 1), [ "a" ])
AssertScreenCharsInRectEqual(Rect(3, 1, 3, 1), [ "b" ])
def test_DECSTR_DECLRMM(self):
# This isn't in the vt 510 docs but xterm does it and it makes sense to do.
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(5, 6)
# Perform soft reset
esccmd.DECSTR()
# Ensure margins are gone.
esccmd.CUP(Point(5, 5))
escio.Write("ab")
AssertEQ(GetCursorPosition().x(), 7)
def test_DECSTR_CursorStaysPut(self):
esccmd.CUP(Point(5, 6))
esccmd.DECSTR()
position = GetCursorPosition()
AssertEQ(position.x(), 5)
AssertEQ(position.y(), 6)
from esc import NUL
import esccmd
import escio
from esctypes import Point, Rect
from escutil import AssertScreenCharsInRectEqual, GetScreenSize, knownBug
class DLTests(object):
def prepare(self):
"""Fills the screen with 4-char line numbers (0001, 0002, ...) down to the
last line and puts the cursor on the start of the second line."""
height = GetScreenSize().height()
for i in xrange(height):
y = i + 1
esccmd.CUP(Point(1, y))
escio.Write("%04d" % y)
esccmd.CUP(Point(1, 2))
def prepareForRegion(self):
"""Sets the screen up as
abcde
fghij
klmno
pqrst
uvwxy
With the cursor on the 'h'."""
lines = [ "abcde",
"fghij",
"klmno",
"pqrst",
"uvwxy" ]
for i in xrange(len(lines)):
y = i + 1
line = lines[i]
esccmd.CUP(Point(1, y))
escio.Write(line)
esccmd.CUP(Point(3, 2))
def test_DL_DefaultParam(self):
"""DL with no parameter should delete a single line."""
# Set up the screen with 0001, 0002, ..., height
self.prepare()
# Delete the second line, moving subsequent lines up.
esccmd.DL()
# Build an array of 0001, 0003, 0004, ..., height
height = GetScreenSize().height()
y = 1
expected_lines = []
for i in xrange(height):
if y != 2:
expected_lines.append("%04d" % y)
y += 1
# The last line should be blank
expected_lines.append(NUL * 4);
AssertScreenCharsInRectEqual(Rect(1, 1, 4, height), expected_lines);
def test_DL_ExplicitParam(self):
"""DL should delete the given number of lines."""
# Set up the screen with 0001, 0002, ..., height
self.prepare()
# Delete two lines starting at the second line, moving subsequent lines up.
esccmd.DL(2)
# Build an array of 0001, 0004, ..., height
height = GetScreenSize().height()
y = 1
expected_lines = []
for i in xrange(height):
if y < 2 or y > 3:
expected_lines.append("%04d" % y)
y += 1
# The last two lines should be blank
expected_lines.append(NUL * 4);
expected_lines.append(NUL * 4);
AssertScreenCharsInRectEqual(Rect(1, 1, 4, height), expected_lines);
def test_DL_DeleteMoreThanVisible(self):
"""Test passing a too-big parameter to DL."""
# Set up the screen with 0001, 0002, ..., height
self.prepare()
# Delete more than the height of the screen.
height = GetScreenSize().height()
esccmd.DL(height * 2)
# Build an array of 0001 followed by height-1 empty lines.
y = 1
expected_lines = [ "0001" ]
for i in xrange(height - 1):
expected_lines.append(NUL * 4);
AssertScreenCharsInRectEqual(Rect(1, 1, 4, height), expected_lines);
def test_DL_InScrollRegion(self):
"""Test that DL does the right thing when the cursor is inside the scroll
region."""
self.prepareForRegion()
esccmd.DECSTBM(2, 4)
esccmd.CUP(Point(3, 2))
esccmd.DL()
esccmd.DECSTBM()
expected_lines = [ "abcde",
"klmno",
"pqrst",
NUL * 5,
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
def test_DL_OutsideScrollRegion(self):
"""Test that DL does nothing when the cursor is outside the scroll
region."""
self.prepareForRegion()
esccmd.DECSTBM(2, 4)
esccmd.CUP(Point(3, 1))
esccmd.DL()
esccmd.DECSTBM()
expected_lines = [ "abcde",
"fghij",
"klmno",
"pqrst",
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
def test_DL_InLeftRightScrollRegion(self):
"""Test that DL respects left-right margins."""
self.prepareForRegion()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(3, 2))
esccmd.DL()
esccmd.DECRESET(esccmd.DECLRMM)
expected_lines = [ "abcde",
"flmnj",
"kqrso",
"pvwxt",
"u" + NUL * 3 + "y" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
@knownBug(terminal="xterm",
reason="xterm erases the area inside the scroll region incorrectly")
def test_DL_OutsideLeftRightScrollRegion(self):
"""Test that DL does nothing outside a left-right margin."""
self.prepareForRegion()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(1, 2))
esccmd.DL()
esccmd.DECRESET(esccmd.DECLRMM)
expected_lines = [ "abcde",
"fghij",
"klmno",
"pqrst",
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
def test_DL_InLeftRightAndTopBottomScrollRegion(self):
"""Test that DL respects left-right margins together with top-bottom."""
self.prepareForRegion()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 4)
esccmd.CUP(Point(3, 2))
esccmd.DL()
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
expected_lines = [ "abcde",
"flmnj",
"kqrso",
"p" + NUL * 3 + "t",
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
def test_DL_ClearOutLeftRightAndTopBottomScrollRegion(self):
"""Erase the whole scroll region with both kinds of margins."""
self.prepareForRegion()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 4)
esccmd.CUP(Point(3, 2))
esccmd.DL(99)
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
expected_lines = [ "abcde",
"f" + NUL * 3 + "j",
"k" + NUL * 3 + "o",
"p" + NUL * 3 + "t",
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
def test_DL_OutsideLeftRightAndTopBottomScrollRegion(self):
"""Test that DL does nothing outside left-right margins together with top-bottom."""
self.prepareForRegion()
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.DECSTBM(2, 4)
esccmd.CUP(Point(1, 1))
esccmd.DL()
esccmd.DECRESET(esccmd.DECLRMM)
esccmd.DECSTBM()
expected_lines = [ "abcde",
"fghij",
"klmno",
"pqrst",
"uvwxy" ]
AssertScreenCharsInRectEqual(Rect(1, 1, 5, 5), expected_lines);
from esc import NUL, blank
import escargs
import esccmd
import escio
from esctypes import Point, Rect
from escutil import AssertEQ, AssertScreenCharsInRectEqual, GetCursorPosition, GetScreenSize, knownBug
class ECHTests(object):
def test_ECH_DefaultParam(self):
"""Should erase the character under the cursor."""
escio.Write("abc")
esccmd.CUP(Point(1, 1))
esccmd.ECH()
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 1), [ blank() + "bc" ]);
def test_ECH_ExplicitParam(self):
"""Should erase N characters starting at the cursor."""
escio.Write("abc")
esccmd.CUP(Point(1, 1))
esccmd.ECH(2)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 1), [ blank() * 2 + "c" ]);
def test_ECH_IgnoresScrollRegion(self):
"""ECH ignores the scroll region when the cursor is inside it"""
escio.Write("abcdefg")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(3, 1))
esccmd.ECH(4)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 1), [ "ab" + blank() * 4 + "g" ]);
def test_ECH_OutsideScrollRegion(self):
"""ECH ignores the scroll region when the cursor is outside it"""
escio.Write("abcdefg")
esccmd.DECSET(esccmd.DECLRMM)
esccmd.DECSLRM(2, 4)
esccmd.CUP(Point(1, 1))
esccmd.ECH(4)
esccmd.DECRESET(esccmd.DECLRMM)
AssertScreenCharsInRectEqual(Rect(1, 1, 7, 1), [ blank() * 4 + "efg" ]);
@knownBug(terminal="xterm",
reason="ECH respects DEC protection, which is questionable at best given the description of DECSCA 'The selective erase control functions (DECSED and DECSEL) can only erase characters defined as erasable'.")
def test_ECH_doesNotRespectDECPRotection(self):
"""ECH should not respect DECSCA."""
escio.Write("a")
escio.Write("b")
esccmd.DECSCA(1)
escio.Write("c")
esccmd.DECSCA(0)
esccmd.CUP(Point(1, 1))
esccmd.ECH(3)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 1),
[ blank() * 3 ])
@knownBug(terminal="iTerm2",
reason="Protection not implemented.")
def test_ECH_respectsISOProtection(self):
"""ECH respects SPA/EPA."""
escio.Write("a")
escio.Write("b")
esccmd.SPA()
escio.Write("c")
esccmd.EPA()
esccmd.CUP(Point(1, 1))
esccmd.ECH(3)
AssertScreenCharsInRectEqual(Rect(1, 1, 3, 1),
[ blank() * 2 + "c" ])
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