| 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()
|