Home | History | Annotate | Download | only in tests
      1 """Tests for distutils.filelist."""
      2 import os
      3 import re
      4 import unittest
      5 from distutils import debug
      6 from distutils.log import WARN
      7 from distutils.errors import DistutilsTemplateError
      8 from distutils.filelist import glob_to_re, translate_pattern, FileList
      9 from distutils import filelist
     10 
     11 import test.support
     12 from test.support import captured_stdout, run_unittest
     13 from distutils.tests import support
     14 
     15 MANIFEST_IN = """\
     16 include ok
     17 include xo
     18 exclude xo
     19 include foo.tmp
     20 include buildout.cfg
     21 global-include *.x
     22 global-include *.txt
     23 global-exclude *.tmp
     24 recursive-include f *.oo
     25 recursive-exclude global *.x
     26 graft dir
     27 prune dir3
     28 """
     29 
     30 
     31 def make_local_path(s):
     32     """Converts '/' in a string to os.sep"""
     33     return s.replace('/', os.sep)
     34 
     35 
     36 class FileListTestCase(support.LoggingSilencer,
     37                        unittest.TestCase):
     38 
     39     def assertNoWarnings(self):
     40         self.assertEqual(self.get_logs(WARN), [])
     41         self.clear_logs()
     42 
     43     def assertWarnings(self):
     44         self.assertGreater(len(self.get_logs(WARN)), 0)
     45         self.clear_logs()
     46 
     47     def test_glob_to_re(self):
     48         sep = os.sep
     49         if os.sep == '\\':
     50             sep = re.escape(os.sep)
     51 
     52         for glob, regex in (
     53             # simple cases
     54             ('foo*', r'(?s:foo[^%(sep)s]*)\Z'),
     55             ('foo?', r'(?s:foo[^%(sep)s])\Z'),
     56             ('foo??', r'(?s:foo[^%(sep)s][^%(sep)s])\Z'),
     57             # special cases
     58             (r'foo\\*', r'(?s:foo\\\\[^%(sep)s]*)\Z'),
     59             (r'foo\\\*', r'(?s:foo\\\\\\[^%(sep)s]*)\Z'),
     60             ('foo????', r'(?s:foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s])\Z'),
     61             (r'foo\\??', r'(?s:foo\\\\[^%(sep)s][^%(sep)s])\Z')):
     62             regex = regex % {'sep': sep}
     63             self.assertEqual(glob_to_re(glob), regex)
     64 
     65     def test_process_template_line(self):
     66         # testing  all MANIFEST.in template patterns
     67         file_list = FileList()
     68         l = make_local_path
     69 
     70         # simulated file list
     71         file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt',
     72                               'buildout.cfg',
     73                               # filelist does not filter out VCS directories,
     74                               # it's sdist that does
     75                               l('.hg/last-message.txt'),
     76                               l('global/one.txt'),
     77                               l('global/two.txt'),
     78                               l('global/files.x'),
     79                               l('global/here.tmp'),
     80                               l('f/o/f.oo'),
     81                               l('dir/graft-one'),
     82                               l('dir/dir2/graft2'),
     83                               l('dir3/ok'),
     84                               l('dir3/sub/ok.txt'),
     85                              ]
     86 
     87         for line in MANIFEST_IN.split('\n'):
     88             if line.strip() == '':
     89                 continue
     90             file_list.process_template_line(line)
     91 
     92         wanted = ['ok',
     93                   'buildout.cfg',
     94                   'four.txt',
     95                   l('.hg/last-message.txt'),
     96                   l('global/one.txt'),
     97                   l('global/two.txt'),
     98                   l('f/o/f.oo'),
     99                   l('dir/graft-one'),
    100                   l('dir/dir2/graft2'),
    101                  ]
    102 
    103         self.assertEqual(file_list.files, wanted)
    104 
    105     def test_debug_print(self):
    106         file_list = FileList()
    107         with captured_stdout() as stdout:
    108             file_list.debug_print('xxx')
    109         self.assertEqual(stdout.getvalue(), '')
    110 
    111         debug.DEBUG = True
    112         try:
    113             with captured_stdout() as stdout:
    114                 file_list.debug_print('xxx')
    115             self.assertEqual(stdout.getvalue(), 'xxx\n')
    116         finally:
    117             debug.DEBUG = False
    118 
    119     def test_set_allfiles(self):
    120         file_list = FileList()
    121         files = ['a', 'b', 'c']
    122         file_list.set_allfiles(files)
    123         self.assertEqual(file_list.allfiles, files)
    124 
    125     def test_remove_duplicates(self):
    126         file_list = FileList()
    127         file_list.files = ['a', 'b', 'a', 'g', 'c', 'g']
    128         # files must be sorted beforehand (sdist does it)
    129         file_list.sort()
    130         file_list.remove_duplicates()
    131         self.assertEqual(file_list.files, ['a', 'b', 'c', 'g'])
    132 
    133     def test_translate_pattern(self):
    134         # not regex
    135         self.assertTrue(hasattr(
    136             translate_pattern('a', anchor=True, is_regex=False),
    137             'search'))
    138 
    139         # is a regex
    140         regex = re.compile('a')
    141         self.assertEqual(
    142             translate_pattern(regex, anchor=True, is_regex=True),
    143             regex)
    144 
    145         # plain string flagged as regex
    146         self.assertTrue(hasattr(
    147             translate_pattern('a', anchor=True, is_regex=True),
    148             'search'))
    149 
    150         # glob support
    151         self.assertTrue(translate_pattern(
    152             '*.py', anchor=True, is_regex=False).search('filelist.py'))
    153 
    154     def test_exclude_pattern(self):
    155         # return False if no match
    156         file_list = FileList()
    157         self.assertFalse(file_list.exclude_pattern('*.py'))
    158 
    159         # return True if files match
    160         file_list = FileList()
    161         file_list.files = ['a.py', 'b.py']
    162         self.assertTrue(file_list.exclude_pattern('*.py'))
    163 
    164         # test excludes
    165         file_list = FileList()
    166         file_list.files = ['a.py', 'a.txt']
    167         file_list.exclude_pattern('*.py')
    168         self.assertEqual(file_list.files, ['a.txt'])
    169 
    170     def test_include_pattern(self):
    171         # return False if no match
    172         file_list = FileList()
    173         file_list.set_allfiles([])
    174         self.assertFalse(file_list.include_pattern('*.py'))
    175 
    176         # return True if files match
    177         file_list = FileList()
    178         file_list.set_allfiles(['a.py', 'b.txt'])
    179         self.assertTrue(file_list.include_pattern('*.py'))
    180 
    181         # test * matches all files
    182         file_list = FileList()
    183         self.assertIsNone(file_list.allfiles)
    184         file_list.set_allfiles(['a.py', 'b.txt'])
    185         file_list.include_pattern('*')
    186         self.assertEqual(file_list.allfiles, ['a.py', 'b.txt'])
    187 
    188     def test_process_template(self):
    189         l = make_local_path
    190         # invalid lines
    191         file_list = FileList()
    192         for action in ('include', 'exclude', 'global-include',
    193                        'global-exclude', 'recursive-include',
    194                        'recursive-exclude', 'graft', 'prune', 'blarg'):
    195             self.assertRaises(DistutilsTemplateError,
    196                               file_list.process_template_line, action)
    197 
    198         # include
    199         file_list = FileList()
    200         file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')])
    201 
    202         file_list.process_template_line('include *.py')
    203         self.assertEqual(file_list.files, ['a.py'])
    204         self.assertNoWarnings()
    205 
    206         file_list.process_template_line('include *.rb')
    207         self.assertEqual(file_list.files, ['a.py'])
    208         self.assertWarnings()
    209 
    210         # exclude
    211         file_list = FileList()
    212         file_list.files = ['a.py', 'b.txt', l('d/c.py')]
    213 
    214         file_list.process_template_line('exclude *.py')
    215         self.assertEqual(file_list.files, ['b.txt', l('d/c.py')])
    216         self.assertNoWarnings()
    217 
    218         file_list.process_template_line('exclude *.rb')
    219         self.assertEqual(file_list.files, ['b.txt', l('d/c.py')])
    220         self.assertWarnings()
    221 
    222         # global-include
    223         file_list = FileList()
    224         file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')])
    225 
    226         file_list.process_template_line('global-include *.py')
    227         self.assertEqual(file_list.files, ['a.py', l('d/c.py')])
    228         self.assertNoWarnings()
    229 
    230         file_list.process_template_line('global-include *.rb')
    231         self.assertEqual(file_list.files, ['a.py', l('d/c.py')])
    232         self.assertWarnings()
    233 
    234         # global-exclude
    235         file_list = FileList()
    236         file_list.files = ['a.py', 'b.txt', l('d/c.py')]
    237 
    238         file_list.process_template_line('global-exclude *.py')
    239         self.assertEqual(file_list.files, ['b.txt'])
    240         self.assertNoWarnings()
    241 
    242         file_list.process_template_line('global-exclude *.rb')
    243         self.assertEqual(file_list.files, ['b.txt'])
    244         self.assertWarnings()
    245 
    246         # recursive-include
    247         file_list = FileList()
    248         file_list.set_allfiles(['a.py', l('d/b.py'), l('d/c.txt'),
    249                                 l('d/d/e.py')])
    250 
    251         file_list.process_template_line('recursive-include d *.py')
    252         self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
    253         self.assertNoWarnings()
    254 
    255         file_list.process_template_line('recursive-include e *.py')
    256         self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
    257         self.assertWarnings()
    258 
    259         # recursive-exclude
    260         file_list = FileList()
    261         file_list.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
    262 
    263         file_list.process_template_line('recursive-exclude d *.py')
    264         self.assertEqual(file_list.files, ['a.py', l('d/c.txt')])
    265         self.assertNoWarnings()
    266 
    267         file_list.process_template_line('recursive-exclude e *.py')
    268         self.assertEqual(file_list.files, ['a.py', l('d/c.txt')])
    269         self.assertWarnings()
    270 
    271         # graft
    272         file_list = FileList()
    273         file_list.set_allfiles(['a.py', l('d/b.py'), l('d/d/e.py'),
    274                                 l('f/f.py')])
    275 
    276         file_list.process_template_line('graft d')
    277         self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
    278         self.assertNoWarnings()
    279 
    280         file_list.process_template_line('graft e')
    281         self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')])
    282         self.assertWarnings()
    283 
    284         # prune
    285         file_list = FileList()
    286         file_list.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
    287 
    288         file_list.process_template_line('prune d')
    289         self.assertEqual(file_list.files, ['a.py', l('f/f.py')])
    290         self.assertNoWarnings()
    291 
    292         file_list.process_template_line('prune e')
    293         self.assertEqual(file_list.files, ['a.py', l('f/f.py')])
    294         self.assertWarnings()
    295 
    296 
    297 class FindAllTestCase(unittest.TestCase):
    298     @test.support.skip_unless_symlink
    299     def test_missing_symlink(self):
    300         with test.support.temp_cwd():
    301             os.symlink('foo', 'bar')
    302             self.assertEqual(filelist.findall(), [])
    303 
    304     def test_basic_discovery(self):
    305         """
    306         When findall is called with no parameters or with
    307         '.' as the parameter, the dot should be omitted from
    308         the results.
    309         """
    310         with test.support.temp_cwd():
    311             os.mkdir('foo')
    312             file1 = os.path.join('foo', 'file1.txt')
    313             test.support.create_empty_file(file1)
    314             os.mkdir('bar')
    315             file2 = os.path.join('bar', 'file2.txt')
    316             test.support.create_empty_file(file2)
    317             expected = [file2, file1]
    318             self.assertEqual(sorted(filelist.findall()), expected)
    319 
    320     def test_non_local_discovery(self):
    321         """
    322         When findall is called with another path, the full
    323         path name should be returned.
    324         """
    325         with test.support.temp_dir() as temp_dir:
    326             file1 = os.path.join(temp_dir, 'file1.txt')
    327             test.support.create_empty_file(file1)
    328             expected = [file1]
    329             self.assertEqual(filelist.findall(temp_dir), expected)
    330 
    331 
    332 def test_suite():
    333     return unittest.TestSuite([
    334         unittest.makeSuite(FileListTestCase),
    335         unittest.makeSuite(FindAllTestCase),
    336     ])
    337 
    338 
    339 if __name__ == "__main__":
    340     run_unittest(test_suite())
    341