test_walk.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. """Tests for scandir.walk(), copied from CPython's tests for os.walk()."""
  2. import os
  3. import shutil
  4. import sys
  5. import unittest
  6. import scandir
  7. import yatest.common
  8. walk_func = scandir.walk
  9. IS_PY3 = sys.version_info >= (3, 0)
  10. class TestWalk(unittest.TestCase):
  11. testfn = os.path.join(os.path.dirname(__file__), 'temp')
  12. def test_traversal(self):
  13. self.testfn = yatest.common.test_output_path('temp')
  14. # Build:
  15. # TESTFN/
  16. # TEST1/ a file kid and two directory kids
  17. # tmp1
  18. # SUB1/ a file kid and a directory kid
  19. # tmp2
  20. # SUB11/ no kids
  21. # SUB2/ a file kid and a dirsymlink kid
  22. # tmp3
  23. # link/ a symlink to TESTFN.2
  24. # TEST2/
  25. # tmp4 a lone file
  26. walk_path = os.path.join(self.testfn, "TEST1")
  27. sub1_path = os.path.join(walk_path, "SUB1")
  28. sub11_path = os.path.join(sub1_path, "SUB11")
  29. sub2_path = os.path.join(walk_path, "SUB2")
  30. tmp1_path = os.path.join(walk_path, "tmp1")
  31. tmp2_path = os.path.join(sub1_path, "tmp2")
  32. tmp3_path = os.path.join(sub2_path, "tmp3")
  33. link_path = os.path.join(sub2_path, "link")
  34. t2_path = os.path.join(self.testfn, "TEST2")
  35. tmp4_path = os.path.join(self.testfn, "TEST2", "tmp4")
  36. # Create stuff.
  37. os.makedirs(sub11_path)
  38. os.makedirs(sub2_path)
  39. os.makedirs(t2_path)
  40. for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path:
  41. f = open(path, "w")
  42. f.write("I'm " + path + " and proud of it. Blame test_os.\n")
  43. f.close()
  44. has_symlink = hasattr(os, "symlink")
  45. if has_symlink:
  46. try:
  47. if IS_PY3:
  48. os.symlink(os.path.abspath(t2_path), link_path, target_is_directory=True)
  49. else:
  50. os.symlink(os.path.abspath(t2_path), link_path)
  51. sub2_tree = (sub2_path, ["link"], ["tmp3"])
  52. except NotImplementedError:
  53. sub2_tree = (sub2_path, [], ["tmp3"])
  54. else:
  55. sub2_tree = (sub2_path, [], ["tmp3"])
  56. # Walk top-down.
  57. all = list(walk_func(walk_path))
  58. self.assertEqual(len(all), 4)
  59. # We can't know which order SUB1 and SUB2 will appear in.
  60. # Not flipped: TESTFN, SUB1, SUB11, SUB2
  61. # flipped: TESTFN, SUB2, SUB1, SUB11
  62. flipped = all[0][1][0] != "SUB1"
  63. all[0][1].sort()
  64. self.assertEqual(all[0], (walk_path, ["SUB1", "SUB2"], ["tmp1"]))
  65. self.assertEqual(all[1 + flipped], (sub1_path, ["SUB11"], ["tmp2"]))
  66. self.assertEqual(all[2 + flipped], (sub11_path, [], []))
  67. self.assertEqual(all[3 - 2 * flipped], sub2_tree)
  68. # Prune the search.
  69. all = []
  70. for root, dirs, files in walk_func(walk_path):
  71. all.append((root, dirs, files))
  72. # Don't descend into SUB1.
  73. if 'SUB1' in dirs:
  74. # Note that this also mutates the dirs we appended to all!
  75. dirs.remove('SUB1')
  76. self.assertEqual(len(all), 2)
  77. self.assertEqual(all[0], (walk_path, ["SUB2"], ["tmp1"]))
  78. self.assertEqual(all[1], sub2_tree)
  79. # Walk bottom-up.
  80. all = list(walk_func(walk_path, topdown=False))
  81. self.assertEqual(len(all), 4)
  82. # We can't know which order SUB1 and SUB2 will appear in.
  83. # Not flipped: SUB11, SUB1, SUB2, TESTFN
  84. # flipped: SUB2, SUB11, SUB1, TESTFN
  85. flipped = all[3][1][0] != "SUB1"
  86. all[3][1].sort()
  87. self.assertEqual(all[3], (walk_path, ["SUB1", "SUB2"], ["tmp1"]))
  88. self.assertEqual(all[flipped], (sub11_path, [], []))
  89. self.assertEqual(all[flipped + 1], (sub1_path, ["SUB11"], ["tmp2"]))
  90. self.assertEqual(all[2 - 2 * flipped], sub2_tree)
  91. if has_symlink:
  92. # Walk, following symlinks.
  93. for root, dirs, files in walk_func(walk_path, followlinks=True):
  94. if root == link_path:
  95. self.assertEqual(dirs, [])
  96. self.assertEqual(files, ["tmp4"])
  97. break
  98. else:
  99. self.fail("Didn't follow symlink with followlinks=True")
  100. # Test creating a directory and adding it to dirnames
  101. sub3_path = os.path.join(walk_path, "SUB3")
  102. all = []
  103. for root, dirs, files in walk_func(walk_path):
  104. all.append((root, dirs, files))
  105. if 'SUB1' in dirs:
  106. os.makedirs(sub3_path)
  107. dirs.append('SUB3')
  108. all.sort()
  109. self.assertEqual(os.path.split(all[-1][0])[1], 'SUB3')
  110. def tearDown(self):
  111. # Tear everything down. This is a decent use for bottom-up on
  112. # Windows, which doesn't have a recursive delete command. The
  113. # (not so) subtlety is that rmdir will fail unless the dir's
  114. # kids are removed first, so bottom up is essential.
  115. for root, dirs, files in os.walk(self.testfn, topdown=False):
  116. for name in files:
  117. os.remove(os.path.join(root, name))
  118. for name in dirs:
  119. dirname = os.path.join(root, name)
  120. if not os.path.islink(dirname):
  121. os.rmdir(dirname)
  122. else:
  123. os.remove(dirname)
  124. os.rmdir(self.testfn)
  125. class TestWalkSymlink(unittest.TestCase):
  126. temp_dir = os.path.join(os.path.dirname(__file__), 'temp')
  127. def setUp(self):
  128. self.temp_dir = yatest.common.test_output_path('temp')
  129. os.mkdir(self.temp_dir)
  130. self.dir_name = os.path.join(self.temp_dir, 'dir')
  131. os.mkdir(self.dir_name)
  132. open(os.path.join(self.dir_name, 'subfile'), 'w').close()
  133. self.file_name = os.path.join(self.temp_dir, 'file')
  134. open(self.file_name, 'w').close()
  135. def tearDown(self):
  136. shutil.rmtree(self.temp_dir)
  137. def test_symlink_to_file(self):
  138. if not hasattr(os, 'symlink'):
  139. return
  140. try:
  141. os.symlink(self.file_name, os.path.join(self.temp_dir,
  142. 'link_to_file'))
  143. except NotImplementedError:
  144. # Windows versions before Vista don't support symbolic links
  145. return
  146. output = sorted(walk_func(self.temp_dir))
  147. dirs = sorted(output[0][1])
  148. files = sorted(output[0][2])
  149. self.assertEqual(dirs, ['dir'])
  150. self.assertEqual(files, ['file', 'link_to_file'])
  151. self.assertEqual(len(output), 2)
  152. self.assertEqual(output[1][1], [])
  153. self.assertEqual(output[1][2], ['subfile'])
  154. def test_symlink_to_directory(self):
  155. if not hasattr(os, 'symlink'):
  156. return
  157. link_name = os.path.join(self.temp_dir, 'link_to_dir')
  158. try:
  159. if IS_PY3:
  160. os.symlink(self.dir_name, link_name, target_is_directory=True)
  161. else:
  162. os.symlink(self.dir_name, link_name)
  163. except NotImplementedError:
  164. # Windows versions before Vista don't support symbolic links
  165. return
  166. output = sorted(walk_func(self.temp_dir))
  167. dirs = sorted(output[0][1])
  168. files = sorted(output[0][2])
  169. self.assertEqual(dirs, ['dir', 'link_to_dir'])
  170. self.assertEqual(files, ['file'])
  171. self.assertEqual(len(output), 2)
  172. self.assertEqual(output[1][1], [])
  173. self.assertEqual(output[1][2], ['subfile'])
  174. output = sorted(walk_func(self.temp_dir, followlinks=True))
  175. dirs = sorted(output[0][1])
  176. files = sorted(output[0][2])
  177. self.assertEqual(dirs, ['dir', 'link_to_dir'])
  178. self.assertEqual(files, ['file'])
  179. self.assertEqual(len(output), 3)
  180. self.assertEqual(output[1][1], [])
  181. self.assertEqual(output[1][2], ['subfile'])
  182. self.assertEqual(os.path.basename(output[2][0]), 'link_to_dir')
  183. self.assertEqual(output[2][1], [])
  184. self.assertEqual(output[2][2], ['subfile'])