| 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()
|