OILS / osh / history_test.py View on Github | oilshell.org

126 lines, 81 significant
1#!/usr/bin/env python2
2"""
3history_test.py: Tests for history.py
4"""
5from __future__ import print_function
6
7import unittest
8import sys
9
10from core import test_lib
11from core import util
12from osh import history # module under test
13from frontend import parse_lib
14
15# TODO: This can be replaced by the real thing! Call read_history_file
16
17
18class _MockReadlineHistory(object):
19
20 def __init__(self, items):
21 self.items = items
22
23 def get_current_history_length(self):
24 return len(self.items)
25
26 def get_history_item(self, one_based_index):
27 try:
28 return self.items[one_based_index - 1]
29 except IndexError:
30 return None # matches what readline does
31
32
33def _MakeHistoryEvaluator(history_items):
34 parse_ctx = test_lib.InitParseContext()
35 parse_ctx.Init_Trail(parse_lib.Trail())
36
37 debug_f = util.DebugFile(sys.stdout)
38 readline = _MockReadlineHistory(history_items)
39 return history.Evaluator(readline, parse_ctx, debug_f)
40
41
42class HistoryEvaluatorTest(unittest.TestCase):
43
44 def testInvalidHistoryItems(self):
45 hist_ev = _MakeHistoryEvaluator([
46 '(',
47 ])
48 # If you can't parse a command, then it uses the "trail", which is somewhat
49 # ill-defined, but causes an error in this case.
50 self.assertRaises(util.HistoryError, hist_ev.Eval, 'echo !$')
51
52 hist_ev = _MakeHistoryEvaluator([
53 'a( )',
54 ])
55 self.assertRaises(util.HistoryError, hist_ev.Eval, 'echo !$')
56
57 def testReplacements(self):
58 hist_ev = _MakeHistoryEvaluator([
59 'echo 1',
60 'echo ${two:-}',
61 'ls /echo/',
62 ])
63
64 self.assertEqual('echo hi', hist_ev.Eval('echo hi'))
65
66 # Search for prefix
67 self.assertEqual('echo ${two:-}\n', hist_ev.Eval('!echo\n'))
68 # Search for substring
69 self.assertEqual('echo ${two:-} ', hist_ev.Eval('!?two '))
70
71 # Indexes and negative indexes
72 self.assertEqual('echo 1', hist_ev.Eval('!1'))
73 self.assertEqual('ls /echo/', hist_ev.Eval('!-1'))
74 self.assertEqual('echo ${two:-}', hist_ev.Eval('!-2'))
75
76 self.assertRaises(util.HistoryError, hist_ev.Eval, 'echo !-999')
77 self.assertRaises(util.HistoryError, hist_ev.Eval, '!999')
78
79 self.assertEqual('ls /echo/', hist_ev.Eval('!!'))
80
81 self.assertEqual('echo /echo/', hist_ev.Eval('echo !$'))
82
83 def testBug(self):
84 hist_ev = _MakeHistoryEvaluator([
85 'echo ${two:-}',
86 ])
87 self.assertEqual('echo ${two:-}', hist_ev.Eval('echo !$'))
88
89 # Commented out
90 self.assertEqual('echo hi # !$', hist_ev.Eval('echo hi # !$'))
91
92 # This is not technically a comment, but it's hard to re-lex.
93 self.assertEqual('echo hi#!$', hist_ev.Eval('echo hi#!$'))
94
95 # Workaround: the comment char can be single-quoted.
96 self.assertEqual("echo 'hi#'${two:-}", hist_ev.Eval("echo 'hi#'!$"))
97
98 def testParsing(self):
99 hist_ev = _MakeHistoryEvaluator([
100 'echo 1',
101 'echo $three ${4:-} "${five@P}"',
102 ])
103 self.assertEqual('echo "${five@P}"', hist_ev.Eval('echo !$'))
104 self.assertEqual('echo $three', hist_ev.Eval('echo !^'))
105 self.assertEqual('echo -n $three ${4:-} "${five@P}"',
106 hist_ev.Eval('echo -n !*'))
107
108 def testNonCommands(self):
109 hist_ev = _MakeHistoryEvaluator([
110 'echo hi | wc -l',
111 ])
112 self.assertEqual('echo -l', hist_ev.Eval('echo !$'))
113
114 hist_ev = _MakeHistoryEvaluator([
115 'for i in 1 2 3; do echo xx; done',
116 ])
117 self.assertEqual('echo xx', hist_ev.Eval('echo !$'))
118
119 hist_ev = _MakeHistoryEvaluator([
120 '{ echo yy; }',
121 ])
122 self.assertEqual('echo yy', hist_ev.Eval('echo !$'))
123
124
125if __name__ == '__main__':
126 unittest.main()