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

134 lines, 88 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 import word_eval
20from osh.cmd_parse_test import assertParseSimpleCommand
21
22
23def InitEvaluator():
24 word_ev = test_lib.InitWordEvaluator()
25 test_lib.SetLocalString(word_ev.mem, 'x', '- -- ---')
26 test_lib.SetLocalString(word_ev.mem, 'y', 'y yy')
27 test_lib.SetLocalString(word_ev.mem, 'empty', '')
28 test_lib.SetLocalString(word_ev.mem, 'binding', 'spam=eggs')
29 test_lib.SetLocalString(word_ev.mem, 'binding_with_spaces',
30 'x=green eggs and ham')
31
32 word_ev.mem.SetArgv(['x', 'foo', 'spam=eggs'])
33 return word_ev
34
35
36class RegexTest(unittest.TestCase):
37
38 def testSplitAssignArg(self):
39 CASES = [
40 # var name, op, value
41 ('s', ['s', '', '']),
42 ('value', ['value', '', '']),
43 ('s!', None),
44 ('!', None),
45 ('=s', None),
46 ('s=', ['s', '=', '']),
47 ('s=val', ['s', '=', 'val']),
48 ('s=+', ['s', '=', '+']),
49 ('s+=val!', ['s', '+=', 'val!']),
50 ('s+=+', ['s', '+=', '+']),
51 ]
52
53 for s, expected in CASES:
54 actual = util.RegexSearch(consts.ASSIGN_ARG_RE, s)
55 if actual is None:
56 self.assertEqual(expected, actual) # no match
57 else:
58 _, var_name, _, op, value = actual
59 self.assertEqual(expected, [var_name, op, value])
60
61
62class WordEvalTest(unittest.TestCase):
63
64 def testEvalWordSequence_Errors(self):
65 CASES = [
66 'readonly a[x]=1',
67 'readonly $binding a[x]=1',
68 # There's no word elision! This will be a parse error
69 'declare $empty',
70 ]
71
72 for case in CASES:
73 print()
74 print('\t%s' % case)
75 node = assertParseSimpleCommand(self, case)
76 ev = InitEvaluator()
77 try:
78 argv = ev.EvalWordSequence2(node.words, allow_assign=True)
79 except error.FatalRuntime:
80 pass
81 else:
82 self.fail("%r should have raised ParseError", case)
83
84 def testEvalWordSequence(self):
85 node = assertParseSimpleCommand(self, 'ls foo')
86 self.assertEqual(2, len(node.words), node.words)
87 print()
88 print()
89
90 CASES = [
91 'ls [$x] $y core/a*.py',
92 'local a=1',
93
94 # What to do about these?
95 # Resolve second word then?
96 'builtin local a=1',
97 'command local a=1',
98 'typeset -"$@"',
99 # array=(b c)',
100 'local a=(1 2) "$@"', # static then dynamic
101 'readonly "$@" a=(1 2)', # dynamic then static
102 'declare -rx foo=bar spam=eggs a=(1 2)',
103 'declare $binding',
104 'declare $binding_with_spaces',
105
106 # This can be parsed, but the builtin should reject it
107 'export a=(1 2)',
108 'export A=(["k"]=v)',
109
110 # Hard test cases:
111 #
112 # command export foo=bar
113 # builtin export foo=bar
114 #
115 # b=builtin c=command e=export binding='foo=bar'
116 # $c $e $binding
117 # $b $e $binding
118 ]
119
120 for case in CASES:
121 print()
122 print('\t%s' % case)
123 node = assertParseSimpleCommand(self, case)
124 ev = InitEvaluator()
125 argv = ev.EvalWordSequence2(node.words, allow_assign=True)
126
127 print()
128 print('\tcmd_value:')
129 print(argv)
130 print()
131
132
133if __name__ == '__main__':
134 unittest.main()