mirror of
https://github.com/python/cpython.git
synced 2025-07-17 16:25:18 +00:00

This test doesn't care about order, the underlying filesystem APIs do not guarantee directory listings on subsequent calls will be in the same order.
317 lines
12 KiB
Python
317 lines
12 KiB
Python
import glob
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import unittest
|
|
|
|
from test.support import (TESTFN, skip_unless_symlink,
|
|
can_symlink, create_empty_file, change_cwd)
|
|
|
|
|
|
class GlobTests(unittest.TestCase):
|
|
|
|
def norm(self, *parts):
|
|
return os.path.normpath(os.path.join(self.tempdir, *parts))
|
|
|
|
def joins(self, *tuples):
|
|
return [os.path.join(self.tempdir, *parts) for parts in tuples]
|
|
|
|
def mktemp(self, *parts):
|
|
filename = self.norm(*parts)
|
|
base, file = os.path.split(filename)
|
|
if not os.path.exists(base):
|
|
os.makedirs(base)
|
|
create_empty_file(filename)
|
|
|
|
def setUp(self):
|
|
self.tempdir = TESTFN + "_dir"
|
|
self.mktemp('a', 'D')
|
|
self.mktemp('aab', 'F')
|
|
self.mktemp('.aa', 'G')
|
|
self.mktemp('.bb', 'H')
|
|
self.mktemp('aaa', 'zzzF')
|
|
self.mktemp('ZZZ')
|
|
self.mktemp('EF')
|
|
self.mktemp('a', 'bcd', 'EF')
|
|
self.mktemp('a', 'bcd', 'efg', 'ha')
|
|
if can_symlink():
|
|
os.symlink(self.norm('broken'), self.norm('sym1'))
|
|
os.symlink('broken', self.norm('sym2'))
|
|
os.symlink(os.path.join('a', 'bcd'), self.norm('sym3'))
|
|
|
|
def tearDown(self):
|
|
shutil.rmtree(self.tempdir)
|
|
|
|
def glob(self, *parts, **kwargs):
|
|
if len(parts) == 1:
|
|
pattern = parts[0]
|
|
else:
|
|
pattern = os.path.join(*parts)
|
|
p = os.path.join(self.tempdir, pattern)
|
|
res = glob.glob(p, **kwargs)
|
|
self.assertCountEqual(glob.iglob(p, **kwargs), res)
|
|
bres = [os.fsencode(x) for x in res]
|
|
self.assertCountEqual(glob.glob(os.fsencode(p), **kwargs), bres)
|
|
self.assertCountEqual(glob.iglob(os.fsencode(p), **kwargs), bres)
|
|
return res
|
|
|
|
def assertSequencesEqual_noorder(self, l1, l2):
|
|
l1 = list(l1)
|
|
l2 = list(l2)
|
|
self.assertEqual(set(l1), set(l2))
|
|
self.assertEqual(sorted(l1), sorted(l2))
|
|
|
|
def test_glob_literal(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(self.glob('a'), [self.norm('a')])
|
|
eq(self.glob('a', 'D'), [self.norm('a', 'D')])
|
|
eq(self.glob('aab'), [self.norm('aab')])
|
|
eq(self.glob('zymurgy'), [])
|
|
|
|
res = glob.glob('*')
|
|
self.assertEqual({type(r) for r in res}, {str})
|
|
res = glob.glob(os.path.join(os.curdir, '*'))
|
|
self.assertEqual({type(r) for r in res}, {str})
|
|
|
|
res = glob.glob(b'*')
|
|
self.assertEqual({type(r) for r in res}, {bytes})
|
|
res = glob.glob(os.path.join(os.fsencode(os.curdir), b'*'))
|
|
self.assertEqual({type(r) for r in res}, {bytes})
|
|
|
|
def test_glob_one_directory(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa']))
|
|
eq(self.glob('*a'), map(self.norm, ['a', 'aaa']))
|
|
eq(self.glob('.*'), map(self.norm, ['.aa', '.bb']))
|
|
eq(self.glob('?aa'), map(self.norm, ['aaa']))
|
|
eq(self.glob('aa?'), map(self.norm, ['aaa', 'aab']))
|
|
eq(self.glob('aa[ab]'), map(self.norm, ['aaa', 'aab']))
|
|
eq(self.glob('*q'), [])
|
|
|
|
def test_glob_nested_directory(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
if os.path.normcase("abCD") == "abCD":
|
|
# case-sensitive filesystem
|
|
eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF')])
|
|
else:
|
|
# case insensitive filesystem
|
|
eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF'),
|
|
self.norm('a', 'bcd', 'efg')])
|
|
eq(self.glob('a', 'bcd', '*g'), [self.norm('a', 'bcd', 'efg')])
|
|
|
|
def test_glob_directory_names(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(self.glob('*', 'D'), [self.norm('a', 'D')])
|
|
eq(self.glob('*', '*a'), [])
|
|
eq(self.glob('a', '*', '*', '*a'),
|
|
[self.norm('a', 'bcd', 'efg', 'ha')])
|
|
eq(self.glob('?a?', '*F'), [self.norm('aaa', 'zzzF'),
|
|
self.norm('aab', 'F')])
|
|
|
|
def test_glob_directory_with_trailing_slash(self):
|
|
# Patterns ending with a slash shouldn't match non-dirs
|
|
res = glob.glob(self.norm('Z*Z') + os.sep)
|
|
self.assertEqual(res, [])
|
|
res = glob.glob(self.norm('ZZZ') + os.sep)
|
|
self.assertEqual(res, [])
|
|
# When there is a wildcard pattern which ends with os.sep, glob()
|
|
# doesn't blow up.
|
|
res = glob.glob(self.norm('aa*') + os.sep)
|
|
self.assertEqual(len(res), 2)
|
|
# either of these results is reasonable
|
|
self.assertIn(set(res), [
|
|
{self.norm('aaa'), self.norm('aab')},
|
|
{self.norm('aaa') + os.sep, self.norm('aab') + os.sep},
|
|
])
|
|
|
|
def test_glob_bytes_directory_with_trailing_slash(self):
|
|
# Same as test_glob_directory_with_trailing_slash, but with a
|
|
# bytes argument.
|
|
res = glob.glob(os.fsencode(self.norm('Z*Z') + os.sep))
|
|
self.assertEqual(res, [])
|
|
res = glob.glob(os.fsencode(self.norm('ZZZ') + os.sep))
|
|
self.assertEqual(res, [])
|
|
res = glob.glob(os.fsencode(self.norm('aa*') + os.sep))
|
|
self.assertEqual(len(res), 2)
|
|
# either of these results is reasonable
|
|
self.assertIn(set(res), [
|
|
{os.fsencode(self.norm('aaa')),
|
|
os.fsencode(self.norm('aab'))},
|
|
{os.fsencode(self.norm('aaa') + os.sep),
|
|
os.fsencode(self.norm('aab') + os.sep)},
|
|
])
|
|
|
|
@skip_unless_symlink
|
|
def test_glob_symlinks(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(self.glob('sym3'), [self.norm('sym3')])
|
|
eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'),
|
|
self.norm('sym3', 'efg')])
|
|
self.assertIn(self.glob('sym3' + os.sep),
|
|
[[self.norm('sym3')], [self.norm('sym3') + os.sep]])
|
|
eq(self.glob('*', '*F'),
|
|
[self.norm('aaa', 'zzzF'),
|
|
self.norm('aab', 'F'), self.norm('sym3', 'EF')])
|
|
|
|
@skip_unless_symlink
|
|
def test_glob_broken_symlinks(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2'),
|
|
self.norm('sym3')])
|
|
eq(self.glob('sym1'), [self.norm('sym1')])
|
|
eq(self.glob('sym2'), [self.norm('sym2')])
|
|
|
|
@unittest.skipUnless(sys.platform == "win32", "Win32 specific test")
|
|
def test_glob_magic_in_drive(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
eq(glob.glob('*:'), [])
|
|
eq(glob.glob(b'*:'), [])
|
|
eq(glob.glob('?:'), [])
|
|
eq(glob.glob(b'?:'), [])
|
|
eq(glob.glob('\\\\?\\c:\\'), ['\\\\?\\c:\\'])
|
|
eq(glob.glob(b'\\\\?\\c:\\'), [b'\\\\?\\c:\\'])
|
|
eq(glob.glob('\\\\*\\*\\'), [])
|
|
eq(glob.glob(b'\\\\*\\*\\'), [])
|
|
|
|
def check_escape(self, arg, expected):
|
|
self.assertEqual(glob.escape(arg), expected)
|
|
self.assertEqual(glob.escape(os.fsencode(arg)), os.fsencode(expected))
|
|
|
|
def test_escape(self):
|
|
check = self.check_escape
|
|
check('abc', 'abc')
|
|
check('[', '[[]')
|
|
check('?', '[?]')
|
|
check('*', '[*]')
|
|
check('[[_/*?*/_]]', '[[][[]_/[*][?][*]/_]]')
|
|
check('/[[_/*?*/_]]/', '/[[][[]_/[*][?][*]/_]]/')
|
|
|
|
@unittest.skipUnless(sys.platform == "win32", "Win32 specific test")
|
|
def test_escape_windows(self):
|
|
check = self.check_escape
|
|
check('?:?', '?:[?]')
|
|
check('*:*', '*:[*]')
|
|
check(r'\\?\c:\?', r'\\?\c:\[?]')
|
|
check(r'\\*\*\*', r'\\*\*\[*]')
|
|
check('//?/c:/?', '//?/c:/[?]')
|
|
check('//*/*/*', '//*/*/[*]')
|
|
|
|
def rglob(self, *parts, **kwargs):
|
|
return self.glob(*parts, recursive=True, **kwargs)
|
|
|
|
def test_recursive_glob(self):
|
|
eq = self.assertSequencesEqual_noorder
|
|
full = [('EF',), ('ZZZ',),
|
|
('a',), ('a', 'D'),
|
|
('a', 'bcd'),
|
|
('a', 'bcd', 'EF'),
|
|
('a', 'bcd', 'efg'),
|
|
('a', 'bcd', 'efg', 'ha'),
|
|
('aaa',), ('aaa', 'zzzF'),
|
|
('aab',), ('aab', 'F'),
|
|
]
|
|
if can_symlink():
|
|
full += [('sym1',), ('sym2',),
|
|
('sym3',),
|
|
('sym3', 'EF'),
|
|
('sym3', 'efg'),
|
|
('sym3', 'efg', 'ha'),
|
|
]
|
|
eq(self.rglob('**'), self.joins(('',), *full))
|
|
eq(self.rglob(os.curdir, '**'),
|
|
self.joins((os.curdir, ''), *((os.curdir,) + i for i in full)))
|
|
dirs = [('a', ''), ('a', 'bcd', ''), ('a', 'bcd', 'efg', ''),
|
|
('aaa', ''), ('aab', '')]
|
|
if can_symlink():
|
|
dirs += [('sym3', ''), ('sym3', 'efg', '')]
|
|
eq(self.rglob('**', ''), self.joins(('',), *dirs))
|
|
|
|
eq(self.rglob('a', '**'), self.joins(
|
|
('a', ''), ('a', 'D'), ('a', 'bcd'), ('a', 'bcd', 'EF'),
|
|
('a', 'bcd', 'efg'), ('a', 'bcd', 'efg', 'ha')))
|
|
eq(self.rglob('a**'), self.joins(('a',), ('aaa',), ('aab',)))
|
|
expect = [('a', 'bcd', 'EF'), ('EF',)]
|
|
if can_symlink():
|
|
expect += [('sym3', 'EF')]
|
|
eq(self.rglob('**', 'EF'), self.joins(*expect))
|
|
expect = [('a', 'bcd', 'EF'), ('aaa', 'zzzF'), ('aab', 'F'), ('EF',)]
|
|
if can_symlink():
|
|
expect += [('sym3', 'EF')]
|
|
eq(self.rglob('**', '*F'), self.joins(*expect))
|
|
eq(self.rglob('**', '*F', ''), [])
|
|
eq(self.rglob('**', 'bcd', '*'), self.joins(
|
|
('a', 'bcd', 'EF'), ('a', 'bcd', 'efg')))
|
|
eq(self.rglob('a', '**', 'bcd'), self.joins(('a', 'bcd')))
|
|
|
|
with change_cwd(self.tempdir):
|
|
join = os.path.join
|
|
eq(glob.glob('**', recursive=True), [join(*i) for i in full])
|
|
eq(glob.glob(join('**', ''), recursive=True),
|
|
[join(*i) for i in dirs])
|
|
eq(glob.glob(join('**', '*'), recursive=True),
|
|
[join(*i) for i in full])
|
|
eq(glob.glob(join(os.curdir, '**'), recursive=True),
|
|
[join(os.curdir, '')] + [join(os.curdir, *i) for i in full])
|
|
eq(glob.glob(join(os.curdir, '**', ''), recursive=True),
|
|
[join(os.curdir, '')] + [join(os.curdir, *i) for i in dirs])
|
|
eq(glob.glob(join(os.curdir, '**', '*'), recursive=True),
|
|
[join(os.curdir, *i) for i in full])
|
|
eq(glob.glob(join('**','zz*F'), recursive=True),
|
|
[join('aaa', 'zzzF')])
|
|
eq(glob.glob('**zz*F', recursive=True), [])
|
|
expect = [join('a', 'bcd', 'EF'), 'EF']
|
|
if can_symlink():
|
|
expect += [join('sym3', 'EF')]
|
|
eq(glob.glob(join('**', 'EF'), recursive=True), expect)
|
|
|
|
|
|
@skip_unless_symlink
|
|
class SymlinkLoopGlobTests(unittest.TestCase):
|
|
|
|
def test_selflink(self):
|
|
tempdir = TESTFN + "_dir"
|
|
os.makedirs(tempdir)
|
|
self.addCleanup(shutil.rmtree, tempdir)
|
|
with change_cwd(tempdir):
|
|
os.makedirs('dir')
|
|
create_empty_file(os.path.join('dir', 'file'))
|
|
os.symlink(os.curdir, os.path.join('dir', 'link'))
|
|
|
|
results = glob.glob('**', recursive=True)
|
|
self.assertEqual(len(results), len(set(results)))
|
|
results = set(results)
|
|
depth = 0
|
|
while results:
|
|
path = os.path.join(*(['dir'] + ['link'] * depth))
|
|
self.assertIn(path, results)
|
|
results.remove(path)
|
|
if not results:
|
|
break
|
|
path = os.path.join(path, 'file')
|
|
self.assertIn(path, results)
|
|
results.remove(path)
|
|
depth += 1
|
|
|
|
results = glob.glob(os.path.join('**', 'file'), recursive=True)
|
|
self.assertEqual(len(results), len(set(results)))
|
|
results = set(results)
|
|
depth = 0
|
|
while results:
|
|
path = os.path.join(*(['dir'] + ['link'] * depth + ['file']))
|
|
self.assertIn(path, results)
|
|
results.remove(path)
|
|
depth += 1
|
|
|
|
results = glob.glob(os.path.join('**', ''), recursive=True)
|
|
self.assertEqual(len(results), len(set(results)))
|
|
results = set(results)
|
|
depth = 0
|
|
while results:
|
|
path = os.path.join(*(['dir'] + ['link'] * depth + ['']))
|
|
self.assertIn(path, results)
|
|
results.remove(path)
|
|
depth += 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|