test_posixpath.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import unittest
  2. from test import test_support, test_genericpath
  3. from test import test_support as support
  4. import posixpath
  5. import os
  6. import sys
  7. from posixpath import realpath, abspath, dirname, basename
  8. # An absolute path to a temporary filename for testing. We can't rely on TESTFN
  9. # being an absolute path, so we need this.
  10. ABSTFN = abspath(test_support.TESTFN)
  11. def skip_if_ABSTFN_contains_backslash(test):
  12. """
  13. On Windows, posixpath.abspath still returns paths with backslashes
  14. instead of posix forward slashes. If this is the case, several tests
  15. fail, so skip them.
  16. """
  17. found_backslash = '\\' in ABSTFN
  18. msg = "ABSTFN is not a posix path - tests fail"
  19. return [test, unittest.skip(msg)(test)][found_backslash]
  20. def safe_rmdir(dirname):
  21. try:
  22. os.rmdir(dirname)
  23. except OSError:
  24. pass
  25. class PosixPathTest(unittest.TestCase):
  26. def setUp(self):
  27. self.tearDown()
  28. def tearDown(self):
  29. for suffix in ["", "1", "2"]:
  30. test_support.unlink(test_support.TESTFN + suffix)
  31. safe_rmdir(test_support.TESTFN + suffix)
  32. def test_join(self):
  33. self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"), "/bar/baz")
  34. self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
  35. self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"), "/foo/bar/baz/")
  36. def test_split(self):
  37. self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
  38. self.assertEqual(posixpath.split("/"), ("/", ""))
  39. self.assertEqual(posixpath.split("foo"), ("", "foo"))
  40. self.assertEqual(posixpath.split("////foo"), ("////", "foo"))
  41. self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar"))
  42. def splitextTest(self, path, filename, ext):
  43. self.assertEqual(posixpath.splitext(path), (filename, ext))
  44. self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext))
  45. self.assertEqual(posixpath.splitext("abc/" + path), ("abc/" + filename, ext))
  46. self.assertEqual(posixpath.splitext("abc.def/" + path), ("abc.def/" + filename, ext))
  47. self.assertEqual(posixpath.splitext("/abc.def/" + path), ("/abc.def/" + filename, ext))
  48. self.assertEqual(posixpath.splitext(path + "/"), (filename + ext + "/", ""))
  49. def test_splitext(self):
  50. self.splitextTest("foo.bar", "foo", ".bar")
  51. self.splitextTest("foo.boo.bar", "foo.boo", ".bar")
  52. self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar")
  53. self.splitextTest(".csh.rc", ".csh", ".rc")
  54. self.splitextTest("nodots", "nodots", "")
  55. self.splitextTest(".cshrc", ".cshrc", "")
  56. self.splitextTest("...manydots", "...manydots", "")
  57. self.splitextTest("...manydots.ext", "...manydots", ".ext")
  58. self.splitextTest(".", ".", "")
  59. self.splitextTest("..", "..", "")
  60. self.splitextTest("........", "........", "")
  61. self.splitextTest("", "", "")
  62. def test_isabs(self):
  63. self.assertIs(posixpath.isabs(""), False)
  64. self.assertIs(posixpath.isabs("/"), True)
  65. self.assertIs(posixpath.isabs("/foo"), True)
  66. self.assertIs(posixpath.isabs("/foo/bar"), True)
  67. self.assertIs(posixpath.isabs("foo/bar"), False)
  68. def test_basename(self):
  69. self.assertEqual(posixpath.basename("/foo/bar"), "bar")
  70. self.assertEqual(posixpath.basename("/"), "")
  71. self.assertEqual(posixpath.basename("foo"), "foo")
  72. self.assertEqual(posixpath.basename("////foo"), "foo")
  73. self.assertEqual(posixpath.basename("//foo//bar"), "bar")
  74. def test_dirname(self):
  75. self.assertEqual(posixpath.dirname("/foo/bar"), "/foo")
  76. self.assertEqual(posixpath.dirname("/"), "/")
  77. self.assertEqual(posixpath.dirname("foo"), "")
  78. self.assertEqual(posixpath.dirname("////foo"), "////")
  79. self.assertEqual(posixpath.dirname("//foo//bar"), "//foo")
  80. def test_islink(self):
  81. self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False)
  82. f = open(test_support.TESTFN + "1", "wb")
  83. try:
  84. f.write("foo")
  85. f.close()
  86. self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False)
  87. if hasattr(os, "symlink"):
  88. os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
  89. self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True)
  90. os.remove(test_support.TESTFN + "1")
  91. self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True)
  92. self.assertIs(posixpath.exists(test_support.TESTFN + "2"), False)
  93. self.assertIs(posixpath.lexists(test_support.TESTFN + "2"), True)
  94. finally:
  95. if not f.close():
  96. f.close()
  97. def test_samefile(self):
  98. f = open(test_support.TESTFN + "1", "wb")
  99. try:
  100. f.write("foo")
  101. f.close()
  102. self.assertIs(
  103. posixpath.samefile(
  104. test_support.TESTFN + "1",
  105. test_support.TESTFN + "1"
  106. ),
  107. True
  108. )
  109. # If we don't have links, assume that os.stat doesn't return
  110. # reasonable inode information and thus, that samefile() doesn't
  111. # work.
  112. if hasattr(os, "symlink"):
  113. os.symlink(
  114. test_support.TESTFN + "1",
  115. test_support.TESTFN + "2"
  116. )
  117. self.assertIs(
  118. posixpath.samefile(
  119. test_support.TESTFN + "1",
  120. test_support.TESTFN + "2"
  121. ),
  122. True
  123. )
  124. os.remove(test_support.TESTFN + "2")
  125. f = open(test_support.TESTFN + "2", "wb")
  126. f.write("bar")
  127. f.close()
  128. self.assertIs(
  129. posixpath.samefile(
  130. test_support.TESTFN + "1",
  131. test_support.TESTFN + "2"
  132. ),
  133. False
  134. )
  135. finally:
  136. if not f.close():
  137. f.close()
  138. def test_samestat(self):
  139. f = open(test_support.TESTFN + "1", "wb")
  140. try:
  141. f.write("foo")
  142. f.close()
  143. self.assertIs(
  144. posixpath.samestat(
  145. os.stat(test_support.TESTFN + "1"),
  146. os.stat(test_support.TESTFN + "1")
  147. ),
  148. True
  149. )
  150. # If we don't have links, assume that os.stat() doesn't return
  151. # reasonable inode information and thus, that samestat() doesn't
  152. # work.
  153. if hasattr(os, "symlink"):
  154. os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
  155. self.assertIs(
  156. posixpath.samestat(
  157. os.stat(test_support.TESTFN + "1"),
  158. os.stat(test_support.TESTFN + "2")
  159. ),
  160. True
  161. )
  162. os.remove(test_support.TESTFN + "2")
  163. f = open(test_support.TESTFN + "2", "wb")
  164. f.write("bar")
  165. f.close()
  166. self.assertIs(
  167. posixpath.samestat(
  168. os.stat(test_support.TESTFN + "1"),
  169. os.stat(test_support.TESTFN + "2")
  170. ),
  171. False
  172. )
  173. finally:
  174. if not f.close():
  175. f.close()
  176. def test_ismount(self):
  177. self.assertIs(posixpath.ismount("/"), True)
  178. def test_expanduser(self):
  179. self.assertEqual(posixpath.expanduser("foo"), "foo")
  180. with test_support.EnvironmentVarGuard() as env:
  181. for home in '/', '', '//', '///':
  182. env['HOME'] = home
  183. self.assertEqual(posixpath.expanduser("~"), "/")
  184. self.assertEqual(posixpath.expanduser("~/"), "/")
  185. self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
  186. try:
  187. import pwd
  188. except ImportError:
  189. pass
  190. else:
  191. self.assertIsInstance(posixpath.expanduser("~/"), basestring)
  192. # if home directory == root directory, this test makes no sense
  193. if posixpath.expanduser("~") != '/':
  194. self.assertEqual(
  195. posixpath.expanduser("~") + "/",
  196. posixpath.expanduser("~/")
  197. )
  198. self.assertIsInstance(posixpath.expanduser("~root/"), basestring)
  199. self.assertIsInstance(posixpath.expanduser("~foo/"), basestring)
  200. with test_support.EnvironmentVarGuard() as env:
  201. # expanduser should fall back to using the password database
  202. del env['HOME']
  203. home = pwd.getpwuid(os.getuid()).pw_dir
  204. # $HOME can end with a trailing /, so strip it (see #17809)
  205. home = home.rstrip("/") or '/'
  206. self.assertEqual(posixpath.expanduser("~"), home)
  207. def test_normpath(self):
  208. self.assertEqual(posixpath.normpath(""), ".")
  209. self.assertEqual(posixpath.normpath("/"), "/")
  210. self.assertEqual(posixpath.normpath("//"), "//")
  211. self.assertEqual(posixpath.normpath("///"), "/")
  212. self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar")
  213. self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), "/foo/baz")
  214. self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
  215. @skip_if_ABSTFN_contains_backslash
  216. def test_realpath_curdir(self):
  217. self.assertEqual(realpath('.'), os.getcwd())
  218. self.assertEqual(realpath('./.'), os.getcwd())
  219. self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
  220. @skip_if_ABSTFN_contains_backslash
  221. def test_realpath_pardir(self):
  222. self.assertEqual(realpath('..'), dirname(os.getcwd()))
  223. self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
  224. self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
  225. if hasattr(os, "symlink"):
  226. def test_realpath_basic(self):
  227. # Basic operation.
  228. try:
  229. os.symlink(ABSTFN+"1", ABSTFN)
  230. self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
  231. finally:
  232. test_support.unlink(ABSTFN)
  233. def test_realpath_symlink_loops(self):
  234. # Bug #930024, return the path unchanged if we get into an infinite
  235. # symlink loop.
  236. try:
  237. os.symlink(ABSTFN, ABSTFN)
  238. self.assertEqual(realpath(ABSTFN), ABSTFN)
  239. os.symlink(ABSTFN+"1", ABSTFN+"2")
  240. os.symlink(ABSTFN+"2", ABSTFN+"1")
  241. self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
  242. self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
  243. self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
  244. self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
  245. self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
  246. os.symlink(ABSTFN+"x", ABSTFN+"y")
  247. self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
  248. ABSTFN + "y")
  249. self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
  250. ABSTFN + "1")
  251. os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
  252. self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
  253. os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
  254. basename(ABSTFN) + "c", ABSTFN+"c")
  255. self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
  256. # Test using relative path as well.
  257. with support.change_cwd(dirname(ABSTFN)):
  258. self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
  259. finally:
  260. test_support.unlink(ABSTFN)
  261. test_support.unlink(ABSTFN+"1")
  262. test_support.unlink(ABSTFN+"2")
  263. test_support.unlink(ABSTFN+"y")
  264. test_support.unlink(ABSTFN+"c")
  265. test_support.unlink(ABSTFN+"a")
  266. def test_realpath_repeated_indirect_symlinks(self):
  267. # Issue #6975.
  268. try:
  269. os.mkdir(ABSTFN)
  270. os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
  271. os.symlink('self/self/self', ABSTFN + '/link')
  272. self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
  273. finally:
  274. test_support.unlink(ABSTFN + '/self')
  275. test_support.unlink(ABSTFN + '/link')
  276. safe_rmdir(ABSTFN)
  277. def test_realpath_deep_recursion(self):
  278. depth = 10
  279. try:
  280. os.mkdir(ABSTFN)
  281. for i in range(depth):
  282. os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
  283. os.symlink('.', ABSTFN + '/0')
  284. self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
  285. # Test using relative path as well.
  286. with support.change_cwd(ABSTFN):
  287. self.assertEqual(realpath('%d' % depth), ABSTFN)
  288. finally:
  289. for i in range(depth + 1):
  290. test_support.unlink(ABSTFN + '/%d' % i)
  291. safe_rmdir(ABSTFN)
  292. def test_realpath_resolve_parents(self):
  293. # We also need to resolve any symlinks in the parents of a relative
  294. # path passed to realpath. E.g.: current working directory is
  295. # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
  296. # realpath("a"). This should return /usr/share/doc/a/.
  297. try:
  298. os.mkdir(ABSTFN)
  299. os.mkdir(ABSTFN + "/y")
  300. os.symlink(ABSTFN + "/y", ABSTFN + "/k")
  301. with support.change_cwd(ABSTFN + "/k"):
  302. self.assertEqual(realpath("a"), ABSTFN + "/y/a")
  303. finally:
  304. test_support.unlink(ABSTFN + "/k")
  305. safe_rmdir(ABSTFN + "/y")
  306. safe_rmdir(ABSTFN)
  307. def test_realpath_resolve_before_normalizing(self):
  308. # Bug #990669: Symbolic links should be resolved before we
  309. # normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
  310. # in the following hierarchy:
  311. # a/k/y
  312. #
  313. # and a symbolic link 'link-y' pointing to 'y' in directory 'a',
  314. # then realpath("link-y/..") should return 'k', not 'a'.
  315. try:
  316. os.mkdir(ABSTFN)
  317. os.mkdir(ABSTFN + "/k")
  318. os.mkdir(ABSTFN + "/k/y")
  319. os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
  320. # Absolute path.
  321. self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
  322. # Relative path.
  323. with support.change_cwd(dirname(ABSTFN)):
  324. self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
  325. ABSTFN + "/k")
  326. finally:
  327. test_support.unlink(ABSTFN + "/link-y")
  328. safe_rmdir(ABSTFN + "/k/y")
  329. safe_rmdir(ABSTFN + "/k")
  330. safe_rmdir(ABSTFN)
  331. def test_realpath_resolve_first(self):
  332. # Bug #1213894: The first component of the path, if not absolute,
  333. # must be resolved too.
  334. try:
  335. os.mkdir(ABSTFN)
  336. os.mkdir(ABSTFN + "/k")
  337. os.symlink(ABSTFN, ABSTFN + "link")
  338. with support.change_cwd(dirname(ABSTFN)):
  339. base = basename(ABSTFN)
  340. self.assertEqual(realpath(base + "link"), ABSTFN)
  341. self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
  342. finally:
  343. test_support.unlink(ABSTFN + "link")
  344. safe_rmdir(ABSTFN + "/k")
  345. safe_rmdir(ABSTFN)
  346. def test_relpath(self):
  347. (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
  348. try:
  349. curdir = os.path.split(os.getcwd())[-1]
  350. self.assertRaises(ValueError, posixpath.relpath, "")
  351. self.assertEqual(posixpath.relpath("a"), "a")
  352. self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
  353. self.assertEqual(posixpath.relpath("a/b"), "a/b")
  354. self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
  355. self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
  356. self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+curdir+"/a/b")
  357. self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
  358. self.assertEqual(posixpath.relpath("a", "a"), ".")
  359. self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat')
  360. self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat')
  361. self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat')
  362. self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..')
  363. self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat')
  364. self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x')
  365. self.assertEqual(posixpath.relpath("/", "/"), '.')
  366. self.assertEqual(posixpath.relpath("/a", "/a"), '.')
  367. self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.')
  368. finally:
  369. os.getcwd = real_getcwd
  370. @test_support.requires_unicode
  371. def test_expandvars_nonascii_word(self):
  372. encoding = sys.getfilesystemencoding()
  373. # Non-ASCII word characters
  374. letters = test_support.u(r'\xe6\u0130\u0141\u03c6\u041a\u05d0\u062a\u0e01')
  375. uwnonascii = letters.encode(encoding, 'ignore').decode(encoding)[:3]
  376. swnonascii = uwnonascii.encode(encoding)
  377. if not swnonascii:
  378. self.skipTest('Needs non-ASCII word characters')
  379. with test_support.EnvironmentVarGuard() as env:
  380. env.clear()
  381. env[swnonascii] = 'baz' + swnonascii
  382. self.assertEqual(posixpath.expandvars(u'$%s bar' % uwnonascii),
  383. u'baz%s bar' % uwnonascii)
  384. class PosixCommonTest(test_genericpath.CommonTest):
  385. pathmodule = posixpath
  386. attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
  387. def test_main():
  388. test_support.run_unittest(PosixPathTest, PosixCommonTest)
  389. if __name__=="__main__":
  390. test_main()