| 1 | #!/usr/bin/env python2
 | 
| 2 | """
 | 
| 3 | word_test.py: Tests for word_.py
 | 
| 4 | """
 | 
| 5 | from __future__ import print_function
 | 
| 6 | 
 | 
| 7 | import unittest
 | 
| 8 | 
 | 
| 9 | from _devbuild.gen.id_kind_asdl import Id
 | 
| 10 | from _devbuild.gen.syntax_asdl import word_part_e
 | 
| 11 | 
 | 
| 12 | from core import test_lib
 | 
| 13 | from mycpp.mylib import log
 | 
| 14 | from osh import cmd_parse  # reparse input
 | 
| 15 | from osh.cmd_parse_test import assertParseSimpleCommand
 | 
| 16 | from osh.word_parse_test import _assertReadWord
 | 
| 17 | 
 | 
| 18 | from osh import word_  # module under test
 | 
| 19 | 
 | 
| 20 | 
 | 
| 21 | def _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 | 
 | 
| 66 | class 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 | 
 | 
| 175 | if __name__ == '__main__':
 | 
| 176 |     unittest.main()
 |