OILS / osh / glob_test.py View on Github | oils.pub

169 lines, 115 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 testGlobEscapingWithBackslash(self):
31 # This function doubles it
32 self.assertEqual('\\\\', glob_.GlobEscape('\\'))
33 self.assertEqual('\\', glob_.GlobUnescape('\\\\'))
34
35 # This function chooses \@
36 self.assertEqual('\\@', glob_.GlobEscapeBackslash('\\'))
37 self.assertEqual('\\', glob_.GlobUnescapeBackslash('\\@'))
38
39 def testLooksLikeGlob(self):
40 # The way to test bash behavior is:
41 # $ shopt -s nullglob; argv [ # not a glob
42 # $ shopt -s nullglob; argv [] # is a glob
43 # $ shopt -s nullglob; argv [][ # is a glob
44 CASES = [
45 (r'[]', True),
46 (r'[a]', True),
47 (r'[][', True),
48 (r'][', False), # no balanced pair
49 (r'\[]', False), # no balanced pair
50 (r'[', False), # no balanced pair
51 (r']', False), # no balanced pair
52 (r'echo', False),
53 (r'status=0', False),
54 (r'*', True),
55 (r'\*', False),
56 (r'\*.sh', False),
57 ('\\', False),
58 ('*\\', True),
59 ('?', True),
60 ]
61 for pat, expected in CASES:
62 self.assertEqual(expected, glob_.LooksLikeGlob(pat),
63 '%s: expected %r' % (pat, expected))
64
65 def testGlobStripRegexes(self):
66 s = 'aabbccdd'
67
68 # ${v%c*} # shortest suffix
69 m = re.match('^(.*)c.*$', s)
70 self.assertEqual('aabbc', m.group(1))
71
72 # ${v%%c*} # longest suffix
73 m = re.match('^(.*?)c.*$', s)
74 self.assertEqual('aabb', m.group(1))
75
76 # ${v#*b} # shortest prefix
77 m = re.match('^.*?b(.*)$', s)
78 self.assertEqual('bccdd', m.group(1))
79
80 # ${v##*b} # longest prefix
81 m = re.match('^.*b(.*)$', s)
82 self.assertEqual('ccdd', m.group(1))
83
84 def testPatSubRegexes(self):
85 # x=~/git/oils
86 # ${x//git*/X/}
87
88 # git*
89 r1 = re.compile('git.*')
90 result = r1.sub('X', '~/git/oils')
91 self.assertEqual('~/X', result)
92
93 r2 = re.compile('[a-z]')
94 result = r2.sub('X', 'a-b-c')
95 self.assertEqual('X-X-X', result)
96
97 # Substitute the first one only
98 r2 = re.compile('[a-z]')
99 result = r2.sub('X', 'a-b-c', count=1)
100 self.assertEqual('X-b-c', result)
101
102
103def _ReadTokens(s):
104 lex = match.GlobLexer(s)
105 return list(lex.Tokens())
106
107
108class GlobParserTest(unittest.TestCase):
109
110 def testGlobLexer(self):
111 print(_ReadTokens(''))
112 print(_ReadTokens('*.py'))
113 print(_ReadTokens(r'\*.py'))
114 print(_ReadTokens('[abc]'))
115 print(_ReadTokens('\\')) # Enf
116 print(_ReadTokens('\\x'))
117 print(_ReadTokens(r'\\'))
118 print(_ReadTokens(r'[[:alpha:]]'))
119 print(_ReadTokens(r'[?]'))
120
121 def testGlobParser(self):
122 CASES = [
123 # (glob input, expected AST, expected extended regexp, has error)
124 ('*.py', r'.*\.py', False),
125 ('*.?', r'.*\..', False),
126 ('<*>', r'<.*>', False),
127 ('\**+', r'\*.*\+', False),
128 ('\**', r'\*.*', False),
129 ('*.[ch]pp', r'.*\.[ch]pp', False),
130
131 # not globs
132 ('abc', 'abc', False),
133 ('\\*', '\\*', False),
134 ('c:\\foo', 'c:foo', False),
135 ('strange]one', 'strange\\]one', False),
136
137 # character class globs
138 ('[[:space:]abc]', '[[:space:]abc]', False),
139 ('[abc]', '[abc]', False),
140 (r'[\a\b\c]', r'[\a\b\c]', False),
141 ('[abc\[]', r'[abc\[]', False),
142 ('[!not]', '[^not]', False),
143 ('[^also_not]', '[^also_not]', False),
144 ('[!*?!\\[]', '[^*?!\\[]', False),
145 ('[!\]foo]', r'[^]foo]', False),
146
147 # invalid globs
148 ('not_closed[a-z', 'not_closed\\[a-z', True),
149 ('[[:spa[ce:]]', '\\[\\[:spa\\[ce:\\]\\]', True),
150
151 # Regression test for IndexError.
152 ('[', '\\[', True),
153 ('\\', '\\\\', True),
154 (']', '\\]', False),
155 ]
156 for glob, expected_ere, expected_err in CASES:
157 print('===')
158 print(glob)
159 regex, warnings = glob_.GlobToERE(glob)
160 self.assertEqual(
161 expected_ere, regex, 'Expected %r to translate to %r, got %r' %
162 (glob, expected_ere, regex))
163
164 print('regex : %s' % regex)
165 print('warnings: %s' % warnings)
166
167
168if __name__ == '__main__':
169 unittest.main()