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

157 lines, 108 significant
1#!/usr/bin/env python2
2# Copyright 2016 Andy Chu. All rights reserved.
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8"""
9word_eval_test.py: Tests for word_eval.py
10"""
11from __future__ import print_function
12
13import unittest
14
15from core import error
16from core import test_lib
17from core import util
18from frontend import consts
19from osh.cmd_parse_test import assertParseSimpleCommand
20
21
22def InitEvaluator():
23 word_ev = test_lib.InitWordEvaluator()
24 test_lib.SetLocalString(word_ev.mem, 'x', '- -- ---')
25 test_lib.SetLocalString(word_ev.mem, 'y', 'y yy')
26 test_lib.SetLocalString(word_ev.mem, 'empty', '')
27 test_lib.SetLocalString(word_ev.mem, 'binding', 'spam=eggs')
28 test_lib.SetLocalString(word_ev.mem, 'binding_with_spaces',
29 'x=green eggs and ham')
30
31 word_ev.mem.SetArgv(['x', 'foo', 'spam=eggs'])
32 return word_ev
33
34
35class RegexTest(unittest.TestCase):
36
37 def testSplitAssignArg(self):
38 CASES = [
39 # var name, op, value
40 ('s', ['s', '', '']),
41 ('value', ['value', '', '']),
42 ('s!', None),
43 ('!', None),
44 ('=s', None),
45 ('s=', ['s', '=', '']),
46 ('s=val', ['s', '=', 'val']),
47 ('s=+', ['s', '=', '+']),
48 ('s+=val!', ['s', '+=', 'val!']),
49 ('s+=+', ['s', '+=', '+']),
50 ]
51
52 for s, expected in CASES:
53 actual = util.RegexSearch(consts.ASSIGN_ARG_RE, s)
54 if actual is None:
55 self.assertEqual(expected, actual) # no match
56 else:
57 _, var_name, _, op, value = actual
58 self.assertEqual(expected, [var_name, op, value])
59
60 def testTestV(self):
61 CASES = [
62 ('mystr', ['mystr', '']),
63 ('myarray[1]', ['myarray', '1']),
64 ('assoc[name]', ['assoc', 'name']),
65 # Should we allow spaces?
66 ('assoc[name] ', None),
67 ('assoc[name]]', None),
68 ('assoc[name]z', None),
69 ('assoc[name', None),
70 ('not-var', None),
71 ]
72
73 for s, expected in CASES:
74 actual = util.RegexSearch(consts.TEST_V_RE, s)
75 if actual is None:
76 self.assertEqual(expected, actual) # no match
77 else:
78 print(actual)
79 _, name, _, index = actual
80 self.assertEqual(expected, [name, index])
81
82
83class WordEvalTest(unittest.TestCase):
84
85 def testEvalWordSequence_Errors(self):
86 CASES = [
87 'readonly a[x]=1',
88 'readonly $binding a[x]=1',
89 # There's no word elision! This will be a parse error
90 'declare $empty',
91 ]
92
93 for case in CASES:
94 print()
95 print('\t%s' % case)
96 node = assertParseSimpleCommand(self, case)
97 ev = InitEvaluator()
98 try:
99 argv = ev.EvalWordSequence2(node.words,
100 False,
101 allow_assign=True)
102 except error.FatalRuntime:
103 pass
104 else:
105 self.fail("%r should have raised ParseError", case)
106
107 def testEvalWordSequence(self):
108 node = assertParseSimpleCommand(self, 'ls foo')
109 self.assertEqual(2, len(node.words), node.words)
110 print()
111 print()
112
113 CASES = [
114 'ls [$x] $y core/a*.py',
115 'local a=1',
116
117 # What to do about these?
118 # Resolve second word then?
119 'builtin local a=1',
120 'command local a=1',
121 'typeset -"$@"',
122 # array=(b c)',
123 'local a=(1 2) "$@"', # static then dynamic
124 'readonly "$@" a=(1 2)', # dynamic then static
125 'declare -rx foo=bar spam=eggs a=(1 2)',
126 'declare $binding',
127 'declare $binding_with_spaces',
128
129 # This can be parsed, but the builtin should reject it
130 'export a=(1 2)',
131 'export A=(["k"]=v)',
132
133 # Hard test cases:
134 #
135 # command export foo=bar
136 # builtin export foo=bar
137 #
138 # b=builtin c=command e=export binding='foo=bar'
139 # $c $e $binding
140 # $b $e $binding
141 ]
142
143 for case in CASES:
144 print()
145 print('\t%s' % case)
146 node = assertParseSimpleCommand(self, case)
147 ev = InitEvaluator()
148 argv = ev.EvalWordSequence2(node.words, False, allow_assign=True)
149
150 print()
151 print('\tcmd_value:')
152 print(argv)
153 print()
154
155
156if __name__ == '__main__':
157 unittest.main()