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

160 lines, 110 significant
1#!/usr/bin/env python2
2"""
3glob_test.py: Tests for glob.py
4"""
5from __future__ import print_function
6
7import re
8import unittest
9
10from frontend import match
11from osh import glob_
12
13
14class GlobEscapeTest(unittest.TestCase):
15
16 def testEscapeUnescape(self):
17 esc = glob_.GlobEscape
18 unesc = glob_.GlobUnescape
19
20 pairs = [
21 (r'\*.py', '*.py'),
22 (r'\?.py', '?.py'),
23 (r'\[a\-z\]\[\[\:punct\:\]\]', '[a-z][[:punct:]]'),
24 (r'\\n', r'\n'),
25 ]
26 for e, u in pairs:
27 self.assertEqual(e, esc(u))
28 self.assertEqual(u, unesc(e))
29
30 def testLooksLikeGlob(self):
31 # The way to test bash behavior is:
32 # $ shopt -s nullglob; argv [ # not a glob
33 # $ shopt -s nullglob; argv [] # is a glob
34 # $ shopt -s nullglob; argv [][ # is a glob
35 CASES = [
36 (r'[]', True),
37 (r'[a]', True),
38 (r'[][', True),
39 (r'][', False), # no balanced pair
40 (r'\[]', False), # no balanced pair
41 (r'[', False), # no balanced pair
42 (r']', False), # no balanced pair
43 (r'echo', False),
44 (r'status=0', False),
45 (r'*', True),
46 (r'\*', False),
47 (r'\*.sh', False),
48 ('\\', False),
49 ('*\\', True),
50 ('?', True),
51 ]
52 for pat, expected in CASES:
53 self.assertEqual(expected, glob_.LooksLikeGlob(pat),
54 '%s: expected %r' % (pat, expected))
55
56 def testGlobStripRegexes(self):
57 s = 'aabbccdd'
58
59 # ${v%c*} # shortest suffix
60 m = re.match('^(.*)c.*$', s)
61 self.assertEqual('aabbc', m.group(1))
62
63 # ${v%%c*} # longest suffix
64 m = re.match('^(.*?)c.*$', s)
65 self.assertEqual('aabb', m.group(1))
66
67 # ${v#*b} # shortest prefix
68 m = re.match('^.*?b(.*)$', s)
69 self.assertEqual('bccdd', m.group(1))
70
71 # ${v##*b} # longest prefix
72 m = re.match('^.*b(.*)$', s)
73 self.assertEqual('ccdd', m.group(1))
74
75 def testPatSubRegexes(self):
76 # x=~/git/oils
77 # ${x//git*/X/}
78
79 # git*
80 r1 = re.compile('git.*')
81 result = r1.sub('X', '~/git/oils')
82 self.assertEqual('~/X', result)
83
84 r2 = re.compile('[a-z]')
85 result = r2.sub('X', 'a-b-c')
86 self.assertEqual('X-X-X', result)
87
88 # Substitute the first one only
89 r2 = re.compile('[a-z]')
90 result = r2.sub('X', 'a-b-c', count=1)
91 self.assertEqual('X-b-c', result)
92
93
94def _ReadTokens(s):
95 lex = match.GlobLexer(s)
96 return list(lex.Tokens())
97
98
99class GlobParserTest(unittest.TestCase):
100
101 def testGlobLexer(self):
102 print(_ReadTokens(''))
103 print(_ReadTokens('*.py'))
104 print(_ReadTokens(r'\*.py'))
105 print(_ReadTokens('[abc]'))
106 print(_ReadTokens('\\')) # Enf
107 print(_ReadTokens('\\x'))
108 print(_ReadTokens(r'\\'))
109 print(_ReadTokens(r'[[:alpha:]]'))
110 print(_ReadTokens(r'[?]'))
111
112 def testGlobParser(self):
113 CASES = [
114 # (glob input, expected AST, expected extended regexp, has error)
115 ('*.py', r'.*\.py', False),
116 ('*.?', r'.*\..', False),
117 ('<*>', r'<.*>', False),
118 ('\**+', r'\*.*\+', False),
119 ('\**', r'\*.*', False),
120 ('*.[ch]pp', r'.*\.[ch]pp', False),
121
122 # not globs
123 ('abc', 'abc', False),
124 ('\\*', '\\*', False),
125 ('c:\\foo', 'c:foo', False),
126 ('strange]one', 'strange\\]one', False),
127
128 # character class globs
129 ('[[:space:]abc]', '[[:space:]abc]', False),
130 ('[abc]', '[abc]', False),
131 (r'[\a\b\c]', r'[\a\b\c]', False),
132 ('[abc\[]', r'[abc\[]', False),
133 ('[!not]', '[^not]', False),
134 ('[^also_not]', '[^also_not]', False),
135 ('[!*?!\\[]', '[^*?!\\[]', False),
136 ('[!\]foo]', r'[^]foo]', False),
137
138 # invalid globs
139 ('not_closed[a-z', 'not_closed\\[a-z', True),
140 ('[[:spa[ce:]]', '\\[\\[:spa\\[ce:\\]\\]', True),
141
142 # Regression test for IndexError.
143 ('[', '\\[', True),
144 ('\\', '\\\\', True),
145 (']', '\\]', False),
146 ]
147 for glob, expected_ere, expected_err in CASES:
148 print('===')
149 print(glob)
150 regex, warnings = glob_.GlobToERE(glob)
151 self.assertEqual(
152 expected_ere, regex, 'Expected %r to translate to %r, got %r' %
153 (glob, expected_ere, regex))
154
155 print('regex : %s' % regex)
156 print('warnings: %s' % warnings)
157
158
159if __name__ == '__main__':
160 unittest.main()