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

176 lines, 121 significant
1#!/usr/bin/env python2
2"""
3word_test.py: Tests for word_.py
4"""
5from __future__ import print_function
6
7import unittest
8
9from _devbuild.gen.id_kind_asdl import Id
10from _devbuild.gen.syntax_asdl import word_part_e
11
12from core import test_lib
13from mycpp.mylib import log
14from osh import cmd_parse # reparse input
15from osh.cmd_parse_test import assertParseSimpleCommand
16from osh.word_parse_test import _assertReadWord
17
18from osh import word_ # module under test
19
20
21def _DetectAssign(test, word_str, expected):
22 # TODO: This function could be moved to test_lib.
23 log('-' * 80)
24 w = _assertReadWord(test, word_str)
25
26 actual = word_.DetectShAssignment(w)
27 left_token, close_token, part_offset = actual
28
29 expected_left, expected_close, expected_part_offset = expected
30
31 print(left_token, close_token, part_offset)
32 print()
33
34 if expected_left is None:
35 test.assertEqual(None, left_token)
36 else:
37 test.assertEqual(expected_left, left_token.id)
38
39 if expected_close is None:
40 test.assertEqual(None, close_token)
41 else:
42 test.assertEqual(expected_left, left_token.id)
43
44 test.assertEqual(expected_part_offset, part_offset)
45
46 parse_ctx = test_lib.InitParseContext()
47
48 if left_token and left_token.id in (Id.Lit_VarLike, Id.Lit_ArrayLhsOpen):
49 more_env = []
50 preparsed = (left_token, close_token, part_offset, w)
51 try:
52 cmd_parse._AppendMoreEnv([preparsed], more_env)
53 except Exception as e:
54 log('Error: %s', e)
55 else:
56 log('more_env: %s', more_env)
57
58 try:
59 assign_pair = cmd_parse._MakeAssignPair(parse_ctx, preparsed)
60 except Exception as e:
61 log('Error: %s', e)
62 else:
63 log('assign_pair: %s', assign_pair)
64
65
66class WordTest(unittest.TestCase):
67
68 def testDetectLocation(self):
69 CASES = [
70 ('foobar', (None, None, 0)),
71 ('a[x', (None, None, 0)),
72
73 # Empty is not valid, there has to be at least one token.
74 ('a[]=$foo$bar', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 2)),
75 ('a[]+=$foo$bar', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 2)),
76 ('s=1', (Id.Lit_VarLike, None, 1)),
77 ('s+=1', (Id.Lit_VarLike, None, 1)),
78 ('a[x]=1', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 3)),
79 ('a[x]+=1', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 3)),
80 ('a[x++]+=1', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 5)),
81 ('a=(1 2 3)', (Id.Lit_VarLike, None, 1)),
82 ('a+=(1 2 3)', (Id.Lit_VarLike, None, 1)),
83
84 # Empty on RHS
85 ('s=', (Id.Lit_VarLike, None, 1)),
86 ('a[x]=', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 3)),
87
88 # Tilde sub
89 ('s=~foo', (Id.Lit_VarLike, None, 1)),
90 ('a[x]=~', (Id.Lit_ArrayLhsOpen, Id.Lit_ArrayLhsClose, 3)),
91 ]
92 for word_str, expected in CASES:
93 _DetectAssign(self, word_str, expected)
94
95 # These don't parse, as they shouldn't. But not the best error message.
96 #w = assertReadWord(self, 'a[x]=(1 2 3)')
97 #w = assertReadWord(self, 'a[x]+=(1 2 3)')
98
99 TILDE_WORDS = [
100 # These are tilde subs
101 (True, '~'),
102 (True, '~/'),
103 (True, '~/zz'),
104 (True, '~andy'),
105 (True, '~andy/'),
106 (True, '~andy/zz'),
107
108 # These are not
109 (False, '~bob#'),
110 (False, '~bob#/'),
111 (False, '~bob#/zz'),
112 (False, ''),
113 (False, 'foo'),
114 ]
115
116 def testTildeDetect(self):
117 for expected, word_str in self.TILDE_WORDS:
118 w = _assertReadWord(self, word_str)
119 detected = word_.TildeDetect(w)
120 print(detected)
121
122 if detected:
123 self.assertEqual(word_part_e.TildeSub, detected.parts[0].tag())
124 self.assertEqual(True, expected)
125 else:
126 self.assertEqual(False, expected)
127
128 def testTildeDetectAssignColons(self):
129 # x=~a:~b: etc.
130
131 words = [w for _, w in self.TILDE_WORDS]
132 assign_str = ':'.join(words)
133 w = _assertReadWord(self, assign_str)
134 word_.TildeDetectAssign(w)
135
136 print('DETECTED')
137 print(w)
138
139 actual = 0
140 for part in w.parts:
141 if part.tag() == word_part_e.TildeSub:
142 actual += 1
143
144 log('tilde sub parts = %d', actual)
145
146 expected = sum(expected for expected, _ in self.TILDE_WORDS)
147 self.assertEqual(expected, actual)
148
149 print('')
150
151 def testFastStrEval(self):
152 node = assertParseSimpleCommand(self, "ls 'my dir' $x foo/$bar ")
153
154 self.assertEqual(4, len(node.words))
155
156 ls_w = node.words[0]
157 w1 = node.words[1]
158 w2 = node.words[2]
159 w3 = node.words[3]
160
161 self.assertEqual('ls', word_.FastStrEval(ls_w))
162 self.assertEqual('my dir', word_.FastStrEval(w1))
163 self.assertEqual(None, word_.FastStrEval(w2))
164 self.assertEqual(None, word_.FastStrEval(w3))
165
166 # Special case for [ ]
167 node = assertParseSimpleCommand(self, '[ a -lt b ]')
168 self.assertEqual('[', word_.FastStrEval(node.words[0]))
169 self.assertEqual('a', word_.FastStrEval(node.words[1]))
170 self.assertEqual('-lt', word_.FastStrEval(node.words[2]))
171 self.assertEqual('b', word_.FastStrEval(node.words[3]))
172 self.assertEqual(']', word_.FastStrEval(node.words[4]))
173
174
175if __name__ == '__main__':
176 unittest.main()