1 | #!/usr/bin/env python2
|
2 | """
|
3 | glob_test.py: Tests for glob.py
|
4 | """
|
5 | from __future__ import print_function
|
6 |
|
7 | import re
|
8 | import unittest
|
9 |
|
10 | from frontend import match
|
11 | from osh import glob_
|
12 |
|
13 |
|
14 | class 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 |
|
94 | def _ReadTokens(s):
|
95 | lex = match.GlobLexer(s)
|
96 | return list(lex.Tokens())
|
97 |
|
98 |
|
99 | class 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 |
|
159 | if __name__ == '__main__':
|
160 | unittest.main()
|