Imported Upstream version 12.1.0
[contrib/python-twisted.git] / twisted / conch / test / test_helper.py
1 # -*- test-case-name: twisted.conch.test.test_helper -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
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
9
10 from twisted.trial import unittest
11
12 WIDTH = 80
13 HEIGHT = 24
14
15 class BufferTestCase(unittest.TestCase):
16     def setUp(self):
17         self.term = helper.TerminalBuffer()
18         self.term.connectionMade()
19
20     def testInitialState(self):
21         self.assertEqual(self.term.width, WIDTH)
22         self.assertEqual(self.term.height, HEIGHT)
23         self.assertEqual(str(self.term),
24                           '\n' * (HEIGHT - 1))
25         self.assertEqual(self.term.reportCursorPosition(), (0, 0))
26
27
28     def test_initialPrivateModes(self):
29         """
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.
32         """
33         self.assertEqual(
34             {privateModes.AUTO_WRAP: True,
35              privateModes.CURSOR_MODE: True},
36             self.term.privateModes)
37
38
39     def test_carriageReturn(self):
40         """
41         C{"\r"} moves the cursor to the first column in the current row.
42         """
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))
48
49
50     def test_linefeed(self):
51         """
52         C{"\n"} moves the cursor to the next row without changing the column.
53         """
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))
58
59
60     def test_newline(self):
61         """
62         C{write} transforms C{"\n"} into C{"\r\n"}.
63         """
64         self.term.cursorForward(5)
65         self.term.cursorDown(3)
66         self.assertEqual(self.term.reportCursorPosition(), (5, 3))
67         self.term.write("\n")
68         self.assertEqual(self.term.reportCursorPosition(), (0, 4))
69
70
71     def test_setPrivateModes(self):
72         """
73         Verify that L{helper.TerminalBuffer.setPrivateModes} changes the Set
74         Mode (SM) state to "set" for the private modes it is passed.
75         """
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)
81
82
83     def test_resetPrivateModes(self):
84         """
85         Verify that L{helper.TerminalBuffer.resetPrivateModes} changes the Set
86         Mode (SM) state to "reset" for the private modes it is passed.
87         """
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)
93
94
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))
102
103     def testCursorUp(self):
104         self.term.cursorUp(5)
105         self.assertEqual(self.term.reportCursorPosition(), (0, 0))
106
107         self.term.cursorDown(20)
108         self.term.cursorUp(1)
109         self.assertEqual(self.term.reportCursorPosition(), (0, 19))
110
111         self.term.cursorUp(19)
112         self.assertEqual(self.term.reportCursorPosition(), (0, 0))
113
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))
121
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))
132
133     def testCursorPositioning(self):
134         self.term.cursorPosition(3, 9)
135         self.assertEqual(self.term.reportCursorPosition(), (3, 9))
136
137     def testSimpleWriting(self):
138         s = "Hello, world."
139         self.term.write(s)
140         self.assertEqual(
141             str(self.term),
142             s + '\n' +
143             '\n' * (HEIGHT - 2))
144
145     def testOvertype(self):
146         s = "hello, world."
147         self.term.write(s)
148         self.term.cursorBackward(len(s))
149         self.term.resetModes([modes.IRM])
150         self.term.write("H")
151         self.assertEqual(
152             str(self.term),
153             ("H" + s[1:]) + '\n' +
154             '\n' * (HEIGHT - 2))
155
156     def testInsert(self):
157         s = "ello, world."
158         self.term.write(s)
159         self.term.cursorBackward(len(s))
160         self.term.setModes([modes.IRM])
161         self.term.write("H")
162         self.assertEqual(
163             str(self.term),
164             ("H" + s) + '\n' +
165             '\n' * (HEIGHT - 2))
166
167     def testWritingInTheMiddle(self):
168         s = "Hello, world."
169         self.term.cursorDown(5)
170         self.term.cursorForward(5)
171         self.term.write(s)
172         self.assertEqual(
173             str(self.term),
174             '\n' * 5 +
175             (self.term.fill * 5) + s + '\n' +
176             '\n' * (HEIGHT - 7))
177
178     def testWritingWrappedAtEndOfLine(self):
179         s = "Hello, world."
180         self.term.cursorForward(WIDTH - 5)
181         self.term.write(s)
182         self.assertEqual(
183             str(self.term),
184             s[:5].rjust(WIDTH) + '\n' +
185             s[5:] + '\n' +
186             '\n' * (HEIGHT - 3))
187
188     def testIndex(self):
189         self.term.index()
190         self.assertEqual(self.term.reportCursorPosition(), (0, 1))
191         self.term.cursorDown(HEIGHT)
192         self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1))
193         self.term.index()
194         self.assertEqual(self.term.reportCursorPosition(), (0, HEIGHT - 1))
195
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))
203
204     def test_nextLine(self):
205         """
206         C{nextLine} positions the cursor at the beginning of the row below the
207         current row.
208         """
209         self.term.nextLine()
210         self.assertEqual(self.term.reportCursorPosition(), (0, 1))
211         self.term.cursorForward(5)
212         self.assertEqual(self.term.reportCursorPosition(), (5, 1))
213         self.term.nextLine()
214         self.assertEqual(self.term.reportCursorPosition(), (0, 2))
215
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))
226
227     def testSingleShifts(self):
228         self.term.singleShift2()
229         self.term.write('Hi')
230
231         ch = self.term.getCharacter(0, 0)
232         self.assertEqual(ch[0], 'H')
233         self.assertEqual(ch[1].charset, G2)
234
235         ch = self.term.getCharacter(1, 0)
236         self.assertEqual(ch[0], 'i')
237         self.assertEqual(ch[1].charset, G0)
238
239         self.term.singleShift3()
240         self.term.write('!!')
241
242         ch = self.term.getCharacter(2, 0)
243         self.assertEqual(ch[0], '!')
244         self.assertEqual(ch[1].charset, G3)
245
246         ch = self.term.getCharacter(3, 0)
247         self.assertEqual(ch[0], '!')
248         self.assertEqual(ch[1].charset, G0)
249
250     def testShifting(self):
251         s1 = "Hello"
252         s2 = "World"
253         s3 = "Bye!"
254         self.term.write("Hello\n")
255         self.term.shiftOut()
256         self.term.write("World\n")
257         self.term.shiftIn()
258         self.term.write("Bye!\n")
259
260         g = G0
261         h = 0
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
268             h += 1
269
270     def testGraphicRendition(self):
271         self.term.selectGraphicRendition(BOLD, UNDERLINE, BLINK, REVERSE_VIDEO)
272         self.term.write('W')
273         self.term.selectGraphicRendition(NORMAL)
274         self.term.write('X')
275         self.term.selectGraphicRendition(BLINK)
276         self.term.write('Y')
277         self.term.selectGraphicRendition(BOLD)
278         self.term.write('Z')
279
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)
286
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)
293
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)
300
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)
307
308     def testColorAttributes(self):
309         s1 = "Merry xmas"
310         s2 = "Just kidding"
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")
316
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)
327
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)
338
339     def testEraseLine(self):
340         s1 = 'line 1'
341         s2 = 'line 2'
342         s3 = 'line 3'
343         self.term.write('\n'.join((s1, s2, s3)) + '\n')
344         self.term.cursorPosition(1, 1)
345         self.term.eraseLine()
346
347         self.assertEqual(
348             str(self.term),
349             s1 + '\n' +
350             '\n' +
351             s3 + '\n' +
352             '\n' * (HEIGHT - 4))
353
354     def testEraseToLineEnd(self):
355         s = 'Hello, world.'
356         self.term.write(s)
357         self.term.cursorBackward(5)
358         self.term.eraseToLineEnd()
359         self.assertEqual(
360             str(self.term),
361             s[:-5] + '\n' +
362             '\n' * (HEIGHT - 2))
363
364     def testEraseToLineBeginning(self):
365         s = 'Hello, world.'
366         self.term.write(s)
367         self.term.cursorBackward(5)
368         self.term.eraseToLineBeginning()
369         self.assertEqual(
370             str(self.term),
371             s[-4:].rjust(len(s)) + '\n' +
372             '\n' * (HEIGHT - 2))
373
374     def testEraseDisplay(self):
375         self.term.write('Hello world\n')
376         self.term.write('Goodbye world\n')
377         self.term.eraseDisplay()
378
379         self.assertEqual(
380             str(self.term),
381             '\n' * (HEIGHT - 1))
382
383     def testEraseToDisplayEnd(self):
384         s1 = "Hello world"
385         s2 = "Goodbye world"
386         self.term.write('\n'.join((s1, s2, '')))
387         self.term.cursorPosition(5, 1)
388         self.term.eraseToDisplayEnd()
389
390         self.assertEqual(
391             str(self.term),
392             s1 + '\n' +
393             s2[:5] + '\n' +
394             '\n' * (HEIGHT - 3))
395
396     def testEraseToDisplayBeginning(self):
397         s1 = "Hello world"
398         s2 = "Goodbye world"
399         self.term.write('\n'.join((s1, s2)))
400         self.term.cursorPosition(5, 1)
401         self.term.eraseToDisplayBeginning()
402
403         self.assertEqual(
404             str(self.term),
405             '\n' +
406             s2[6:].rjust(len(s2)) + '\n' +
407             '\n' * (HEIGHT - 3))
408
409     def testLineInsertion(self):
410         s1 = "Hello world"
411         s2 = "Goodbye world"
412         self.term.write('\n'.join((s1, s2)))
413         self.term.cursorPosition(7, 1)
414         self.term.insertLine()
415
416         self.assertEqual(
417             str(self.term),
418             s1 + '\n' +
419             '\n' +
420             s2 + '\n' +
421             '\n' * (HEIGHT - 4))
422
423     def testLineDeletion(self):
424         s1 = "Hello world"
425         s2 = "Middle words"
426         s3 = "Goodbye world"
427         self.term.write('\n'.join((s1, s2, s3)))
428         self.term.cursorPosition(9, 1)
429         self.term.deleteLine()
430
431         self.assertEqual(
432             str(self.term),
433             s1 + '\n' +
434             s3 + '\n' +
435             '\n' * (HEIGHT - 3))
436
437 class FakeDelayedCall:
438     called = False
439     cancelled = False
440     def __init__(self, fs, timeout, f, a, kw):
441         self.fs = fs
442         self.timeout = timeout
443         self.f = f
444         self.a = a
445         self.kw = kw
446
447     def active(self):
448         return not (self.cancelled or self.called)
449
450     def cancel(self):
451         self.cancelled = True
452 #        self.fs.calls.remove(self)
453
454     def call(self):
455         self.called = True
456         self.f(*self.a, **self.kw)
457
458 class FakeScheduler:
459     def __init__(self):
460         self.calls = []
461
462     def callLater(self, timeout, f, *a, **kw):
463         self.calls.append(FakeDelayedCall(self, timeout, f, a, kw))
464         return self.calls[-1]
465
466 class ExpectTestCase(unittest.TestCase):
467     def setUp(self):
468         self.term = helper.ExpectableBuffer()
469         self.term.connectionMade()
470         self.fs = FakeScheduler()
471
472     def testSimpleString(self):
473         result = []
474         d = self.term.expect("hello world", timeout=1, scheduler=self.fs)
475         d.addCallback(result.append)
476
477         self.term.write("greeting puny earthlings\n")
478         self.failIf(result)
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())
484
485     def testBrokenUpString(self):
486         result = []
487         d = self.term.expect("hello world")
488         d.addCallback(result.append)
489
490         self.failIf(result)
491         self.term.write("hello ")
492         self.failIf(result)
493         self.term.write("worl")
494         self.failIf(result)
495         self.term.write("d")
496         self.failUnless(result)
497         self.assertEqual(result[0].group(), "hello world")
498
499
500     def testMultiple(self):
501         result = []
502         d1 = self.term.expect("hello ")
503         d1.addCallback(result.append)
504         d2 = self.term.expect("world")
505         d2.addCallback(result.append)
506
507         self.failIf(result)
508         self.term.write("hello")
509         self.failIf(result)
510         self.term.write(" ")
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")
516
517     def testSynchronous(self):
518         self.term.write("hello world")
519
520         result = []
521         d = self.term.expect("hello world")
522         d.addCallback(result.append)
523         self.failUnless(result)
524         self.assertEqual(result[0].group(), "hello world")
525
526     def testMultipleSynchronous(self):
527         self.term.write("goodbye world")
528
529         result = []
530         d1 = self.term.expect("bye")
531         d1.addCallback(result.append)
532         d2 = self.term.expect("world")
533         d2.addCallback(result.append)
534
535         self.assertEqual(len(result), 2)
536         self.assertEqual(result[0].group(), "bye")
537         self.assertEqual(result[1].group(), "world")
538
539     def _cbTestTimeoutFailure(self, res):
540         self.assert_(hasattr(res, 'type'))
541         self.assertEqual(res.type, helper.ExpectationTimeout)
542
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()
547
548     def testOverlappingTimeout(self):
549         self.term.write("not zoomtastic")
550
551         result = []
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)
556
557         self.fs.calls[0].call()
558
559         self.assertEqual(len(result), 1)
560         self.assertEqual(result[0].group(), "zoom")