| 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/oil
 | 
| 77 |         # ${x//git*/X/}
 | 
| 78 | 
 | 
| 79 |         # git*
 | 
| 80 |         r1 = re.compile('git.*')
 | 
| 81 |         result = r1.sub('X', '~/git/oil')
 | 
| 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()
 |