1 # -*- test-case-name: twisted.conch.test.test_helper -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
5 from twisted.conch.insults import helper
6 from twisted.conch.insults.insults import G0, G1, G2, G3
7 from twisted.conch.insults.insults import modes, privateModes
8 from twisted.conch.insults.insults import NORMAL, BOLD, UNDERLINE, BLINK, REVERSE_VIDEO
10 from twisted.trial import unittest
15 class BufferTestCase(unittest.TestCase):
17 self.term = helper.TerminalBuffer()
18 self.term.connectionMade()
20 def testInitialState(self):
21 self.assertEqual(self.term.width, WIDTH)
22 self.assertEqual(self.term.height, HEIGHT)
23 self.assertEqual(str(self.term),
25 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
28 def test_initialPrivateModes(self):
30 Verify that only DEC Auto Wrap Mode (DECAWM) and DEC Text Cursor Enable
31 Mode (DECTCEM) are initially in the Set Mode (SM) state.
34 {privateModes.AUTO_WRAP: True,
35 privateModes.CURSOR_MODE: True},
36 self.term.privateModes)
39 def test_carriageReturn(self):
41 C{"\r"} moves the cursor to the first column in the current row.
43 self.term.cursorForward(5)
44 self.term.cursorDown(3)
45 self.assertEqual(self.term.reportCursorPosition(), (5, 3))
46 self.term.insertAtCursor("\r")
47 self.assertEqual(self.term.reportCursorPosition(), (0, 3))
50 def test_linefeed(self):
52 C{"\n"} moves the cursor to the next row without changing the column.
54 self.term.cursorForward(5)
55 self.assertEqual(self.term.reportCursorPosition(), (5, 0))
56 self.term.insertAtCursor("\n")
57 self.assertEqual(self.term.reportCursorPosition(), (5, 1))
60 def test_newline(self):
62 C{write} transforms C{"\n"} into C{"\r\n"}.
64 self.term.cursorForward(5)
65 self.term.cursorDown(3)
66 self.assertEqual(self.term.reportCursorPosition(), (5, 3))
68 self.assertEqual(self.term.reportCursorPosition(), (0, 4))
71 def test_setPrivateModes(self):
73 Verify that L{helper.TerminalBuffer.setPrivateModes} changes the Set
74 Mode (SM) state to "set" for the private modes it is passed.
76 expected = self.term.privateModes.copy()
77 self.term.setPrivateModes([privateModes.SCROLL, privateModes.SCREEN])
78 expected[privateModes.SCROLL] = True
79 expected[privateModes.SCREEN] = True
80 self.assertEqual(expected, self.term.privateModes)
83 def test_resetPrivateModes(self):
85 Verify that L{helper.TerminalBuffer.resetPrivateModes} changes the Set
86 Mode (SM) state to "reset" for the private modes it is passed.
88 expected = self.term.privateModes.copy()
89 self.term.resetPrivateModes([privateModes.AUTO_WRAP, privateModes.CURSOR_MODE])
90 del expected[privateModes.AUTO_WRAP]
91 del expected[privateModes.CURSOR_MODE]
92 self.assertEqual(expected, self.term.privateModes)
95 def testCursorDown(self):
96 self.term.cursorDown(3)
97 self.assertEqual(self.term.reportCursorPosition(), (0, 3))
98 self.term.cursorDown()
99 self.assertEqual(self.term.reportCursorPosition(), (0, 4))
100 self.term.cursorDown(HEIGHT)
101 self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1))
103 def testCursorUp(self):
104 self.term.cursorUp(5)
105 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
107 self.term.cursorDown(20)
108 self.term.cursorUp(1)
109 self.assertEqual(self.term.reportCursorPosition(), (0, 19))
111 self.term.cursorUp(19)
112 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
114 def testCursorForward(self):
115 self.term.cursorForward(2)
116 self.assertEqual(self.term.reportCursorPosition(), (2, 0))
117 self.term.cursorForward(2)
118 self.assertEqual(self.term.reportCursorPosition(), (4, 0))
119 self.term.cursorForward(WIDTH)
120 self.assertEqual(self.term.reportCursorPosition(), (WIDTH, 0))
122 def testCursorBackward(self):
123 self.term.cursorForward(10)
124 self.term.cursorBackward(2)
125 self.assertEqual(self.term.reportCursorPosition(), (8, 0))
126 self.term.cursorBackward(7)
127 self.assertEqual(self.term.reportCursorPosition(), (1, 0))
128 self.term.cursorBackward(1)
129 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
130 self.term.cursorBackward(1)
131 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
133 def testCursorPositioning(self):
134 self.term.cursorPosition(3, 9)
135 self.assertEqual(self.term.reportCursorPosition(), (3, 9))
137 def testSimpleWriting(self):
145 def testOvertype(self):
148 self.term.cursorBackward(len(s))
149 self.term.resetModes([modes.IRM])
153 ("H" + s[1:]) + '\n' +
156 def testInsert(self):
159 self.term.cursorBackward(len(s))
160 self.term.setModes([modes.IRM])
167 def testWritingInTheMiddle(self):
169 self.term.cursorDown(5)
170 self.term.cursorForward(5)
175 (self.term.fill * 5) + s + '\n' +
178 def testWritingWrappedAtEndOfLine(self):
180 self.term.cursorForward(WIDTH - 5)
184 s[:5].rjust(WIDTH) + '\n' +
190 self.assertEqual(self.term.reportCursorPosition(), (0, 1))
191 self.term.cursorDown(HEIGHT)
192 self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1))
194 self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1))
196 def testReverseIndex(self):
197 self.term.reverseIndex()
198 self.assertEqual(self.term.reportCursorPosition(), (0, 0))
199 self.term.cursorDown(2)
200 self.assertEqual(self.term.reportCursorPosition(), (0, 2))
201 self.term.reverseIndex()
202 self.assertEqual(self.term.reportCursorPosition(), (0, 1))
204 def test_nextLine(self):
206 C{nextLine} positions the cursor at the beginning of the row below the
210 self.assertEqual(self.term.reportCursorPosition(), (0, 1))
211 self.term.cursorForward(5)
212 self.assertEqual(self.term.reportCursorPosition(), (5, 1))
214 self.assertEqual(self.term.reportCursorPosition(), (0, 2))
216 def testSaveCursor(self):
217 self.term.cursorDown(5)
218 self.term.cursorForward(7)
219 self.assertEqual(self.term.reportCursorPosition(), (7, 5))
220 self.term.saveCursor()
221 self.term.cursorDown(7)
222 self.term.cursorBackward(3)
223 self.assertEqual(self.term.reportCursorPosition(), (4, 12))
224 self.term.restoreCursor()
225 self.assertEqual(self.term.reportCursorPosition(), (7, 5))
227 def testSingleShifts(self):
228 self.term.singleShift2()
229 self.term.write('Hi')
231 ch = self.term.getCharacter(0, 0)
232 self.assertEqual(ch[0], 'H')
233 self.assertEqual(ch[1].charset, G2)
235 ch = self.term.getCharacter(1, 0)
236 self.assertEqual(ch[0], 'i')
237 self.assertEqual(ch[1].charset, G0)
239 self.term.singleShift3()
240 self.term.write('!!')
242 ch = self.term.getCharacter(2, 0)
243 self.assertEqual(ch[0], '!')
244 self.assertEqual(ch[1].charset, G3)
246 ch = self.term.getCharacter(3, 0)
247 self.assertEqual(ch[0], '!')
248 self.assertEqual(ch[1].charset, G0)
250 def testShifting(self):
254 self.term.write("Hello\n")
256 self.term.write("World\n")
258 self.term.write("Bye!\n")
262 for s in (s1, s2, s3):
263 for i in range(len(s)):
264 ch = self.term.getCharacter(i, h)
265 self.assertEqual(ch[0], s[i])
266 self.assertEqual(ch[1].charset, g)
267 g = g == G0 and G1 or G0
270 def testGraphicRendition(self):
271 self.term.selectGraphicRendition(BOLD, UNDERLINE, BLINK, REVERSE_VIDEO)
273 self.term.selectGraphicRendition(NORMAL)
275 self.term.selectGraphicRendition(BLINK)
277 self.term.selectGraphicRendition(BOLD)
280 ch = self.term.getCharacter(0, 0)
281 self.assertEqual(ch[0], 'W')
282 self.failUnless(ch[1].bold)
283 self.failUnless(ch[1].underline)
284 self.failUnless(ch[1].blink)
285 self.failUnless(ch[1].reverseVideo)
287 ch = self.term.getCharacter(1, 0)
288 self.assertEqual(ch[0], 'X')
289 self.failIf(ch[1].bold)
290 self.failIf(ch[1].underline)
291 self.failIf(ch[1].blink)
292 self.failIf(ch[1].reverseVideo)
294 ch = self.term.getCharacter(2, 0)
295 self.assertEqual(ch[0], 'Y')
296 self.failUnless(ch[1].blink)
297 self.failIf(ch[1].bold)
298 self.failIf(ch[1].underline)
299 self.failIf(ch[1].reverseVideo)
301 ch = self.term.getCharacter(3, 0)
302 self.assertEqual(ch[0], 'Z')
303 self.failUnless(ch[1].blink)
304 self.failUnless(ch[1].bold)
305 self.failIf(ch[1].underline)
306 self.failIf(ch[1].reverseVideo)
308 def testColorAttributes(self):
311 self.term.selectGraphicRendition(helper.FOREGROUND + helper.RED,
312 helper.BACKGROUND + helper.GREEN)
313 self.term.write(s1 + "\n")
314 self.term.selectGraphicRendition(NORMAL)
315 self.term.write(s2 + "\n")
317 for i in range(len(s1)):
318 ch = self.term.getCharacter(i, 0)
319 self.assertEqual(ch[0], s1[i])
320 self.assertEqual(ch[1].charset, G0)
321 self.assertEqual(ch[1].bold, False)
322 self.assertEqual(ch[1].underline, False)
323 self.assertEqual(ch[1].blink, False)
324 self.assertEqual(ch[1].reverseVideo, False)
325 self.assertEqual(ch[1].foreground, helper.RED)
326 self.assertEqual(ch[1].background, helper.GREEN)
328 for i in range(len(s2)):
329 ch = self.term.getCharacter(i, 1)
330 self.assertEqual(ch[0], s2[i])
331 self.assertEqual(ch[1].charset, G0)
332 self.assertEqual(ch[1].bold, False)
333 self.assertEqual(ch[1].underline, False)
334 self.assertEqual(ch[1].blink, False)
335 self.assertEqual(ch[1].reverseVideo, False)
336 self.assertEqual(ch[1].foreground, helper.WHITE)
337 self.assertEqual(ch[1].background, helper.BLACK)
339 def testEraseLine(self):
343 self.term.write('\n'.join((s1, s2, s3)) + '\n')
344 self.term.cursorPosition(1, 1)
345 self.term.eraseLine()
354 def testEraseToLineEnd(self):
357 self.term.cursorBackward(5)
358 self.term.eraseToLineEnd()
364 def testEraseToLineBeginning(self):
367 self.term.cursorBackward(5)
368 self.term.eraseToLineBeginning()
371 s[-4:].rjust(len(s)) + '\n' +
374 def testEraseDisplay(self):
375 self.term.write('Hello world\n')
376 self.term.write('Goodbye world\n')
377 self.term.eraseDisplay()
383 def testEraseToDisplayEnd(self):
386 self.term.write('\n'.join((s1, s2, '')))
387 self.term.cursorPosition(5, 1)
388 self.term.eraseToDisplayEnd()
396 def testEraseToDisplayBeginning(self):
399 self.term.write('\n'.join((s1, s2)))
400 self.term.cursorPosition(5, 1)
401 self.term.eraseToDisplayBeginning()
406 s2[6:].rjust(len(s2)) + '\n' +
409 def testLineInsertion(self):
412 self.term.write('\n'.join((s1, s2)))
413 self.term.cursorPosition(7, 1)
414 self.term.insertLine()
423 def testLineDeletion(self):
427 self.term.write('\n'.join((s1, s2, s3)))
428 self.term.cursorPosition(9, 1)
429 self.term.deleteLine()
437 class FakeDelayedCall:
440 def __init__(self, fs, timeout, f, a, kw):
442 self.timeout = timeout
448 return not (self.cancelled or self.called)
451 self.cancelled = True
452 # self.fs.calls.remove(self)
456 self.f(*self.a, **self.kw)
462 def callLater(self, timeout, f, *a, **kw):
463 self.calls.append(FakeDelayedCall(self, timeout, f, a, kw))
464 return self.calls[-1]
466 class ExpectTestCase(unittest.TestCase):
468 self.term = helper.ExpectableBuffer()
469 self.term.connectionMade()
470 self.fs = FakeScheduler()
472 def testSimpleString(self):
474 d = self.term.expect("hello world", timeout=1, scheduler=self.fs)
475 d.addCallback(result.append)
477 self.term.write("greeting puny earthlings\n")
479 self.term.write("hello world\n")
480 self.failUnless(result)
481 self.assertEqual(result[0].group(), "hello world")
482 self.assertEqual(len(self.fs.calls), 1)
483 self.failIf(self.fs.calls[0].active())
485 def testBrokenUpString(self):
487 d = self.term.expect("hello world")
488 d.addCallback(result.append)
491 self.term.write("hello ")
493 self.term.write("worl")
496 self.failUnless(result)
497 self.assertEqual(result[0].group(), "hello world")
500 def testMultiple(self):
502 d1 = self.term.expect("hello ")
503 d1.addCallback(result.append)
504 d2 = self.term.expect("world")
505 d2.addCallback(result.append)
508 self.term.write("hello")
511 self.assertEqual(len(result), 1)
512 self.term.write("world")
513 self.assertEqual(len(result), 2)
514 self.assertEqual(result[0].group(), "hello ")
515 self.assertEqual(result[1].group(), "world")
517 def testSynchronous(self):
518 self.term.write("hello world")
521 d = self.term.expect("hello world")
522 d.addCallback(result.append)
523 self.failUnless(result)
524 self.assertEqual(result[0].group(), "hello world")
526 def testMultipleSynchronous(self):
527 self.term.write("goodbye world")
530 d1 = self.term.expect("bye")
531 d1.addCallback(result.append)
532 d2 = self.term.expect("world")
533 d2.addCallback(result.append)
535 self.assertEqual(len(result), 2)
536 self.assertEqual(result[0].group(), "bye")
537 self.assertEqual(result[1].group(), "world")
539 def _cbTestTimeoutFailure(self, res):
540 self.assert_(hasattr(res, 'type'))
541 self.assertEqual(res.type, helper.ExpectationTimeout)
543 def testTimeoutFailure(self):
544 d = self.term.expect("hello world", timeout=1, scheduler=self.fs)
545 d.addBoth(self._cbTestTimeoutFailure)
546 self.fs.calls[0].call()
548 def testOverlappingTimeout(self):
549 self.term.write("not zoomtastic")
552 d1 = self.term.expect("hello world", timeout=1, scheduler=self.fs)
553 d1.addBoth(self._cbTestTimeoutFailure)
554 d2 = self.term.expect("zoom")
555 d2.addCallback(result.append)
557 self.fs.calls[0].call()
559 self.assertEqual(len(result), 1)
560 self.assertEqual(result[0].group(), "zoom")