mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +00:00
GH-130614: pathlib ABCs: parametrize test suite for path copying (#131168)
Test copying from `Path` and `ReadableZipPath` (types of `_ReadablePath`) to `Path` and `WritableZipPath` (types of `_WritablePath`).
This commit is contained in:
parent
1a8e5742cd
commit
45c2ef48ca
3 changed files with 173 additions and 139 deletions
|
@ -248,7 +248,7 @@ def copy_file(source, target, follow_symlinks=True, preserve_metadata=False):
|
|||
"""
|
||||
info = source.info
|
||||
if not follow_symlinks and info.is_symlink():
|
||||
target.symlink_to(source.readlink(), info.is_dir())
|
||||
target.symlink_to(str(source.readlink()), info.is_dir())
|
||||
if preserve_metadata:
|
||||
target._write_info(info, follow_symlinks=False)
|
||||
elif info.is_dir():
|
||||
|
|
172
Lib/test/test_pathlib/test_copy.py
Normal file
172
Lib/test/test_pathlib/test_copy.py
Normal file
|
@ -0,0 +1,172 @@
|
|||
"""
|
||||
Tests for copying from pathlib.types._ReadablePath to _WritablePath.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import unittest
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from test.test_pathlib.support.local_path import LocalPathGround, WritableLocalPath
|
||||
from test.test_pathlib.support.zip_path import ZipPathGround, ReadableZipPath, WritableZipPath
|
||||
|
||||
|
||||
class CopyTestBase:
|
||||
def setUp(self):
|
||||
self.source_root = self.source_ground.setup()
|
||||
self.source_ground.create_hierarchy(self.source_root)
|
||||
self.target_root = self.target_ground.setup(local_suffix="_target")
|
||||
|
||||
def tearDown(self):
|
||||
self.source_ground.teardown(self.source_root)
|
||||
self.target_ground.teardown(self.target_root)
|
||||
|
||||
def test_copy_file(self):
|
||||
source = self.source_root / 'fileA'
|
||||
target = self.target_root / 'copyA'
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isfile(target))
|
||||
self.assertEqual(self.source_ground.readbytes(source),
|
||||
self.target_ground.readbytes(result))
|
||||
|
||||
def test_copy_file_empty(self):
|
||||
source = self.source_root / 'empty'
|
||||
target = self.target_root / 'copyA'
|
||||
self.source_ground.create_file(source, b'')
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isfile(target))
|
||||
self.assertEqual(self.target_ground.readbytes(result), b'')
|
||||
|
||||
def test_copy_file_to_existing_file(self):
|
||||
source = self.source_root / 'fileA'
|
||||
target = self.target_root / 'copyA'
|
||||
self.target_ground.create_file(target, b'this is a copy\n')
|
||||
with contextlib.ExitStack() as stack:
|
||||
if isinstance(target, WritableZipPath):
|
||||
stack.enter_context(self.assertWarns(UserWarning))
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isfile(target))
|
||||
self.assertEqual(self.source_ground.readbytes(source),
|
||||
self.target_ground.readbytes(result))
|
||||
|
||||
def test_copy_file_to_directory(self):
|
||||
if not isinstance(self.target_root, WritableLocalPath):
|
||||
self.skipTest('needs local target')
|
||||
source = self.source_root / 'fileA'
|
||||
target = self.target_root / 'copyA'
|
||||
self.target_ground.create_dir(target)
|
||||
self.assertRaises(OSError, source.copy, target)
|
||||
|
||||
def test_copy_file_to_itself(self):
|
||||
source = self.source_root / 'fileA'
|
||||
self.assertRaises(OSError, source.copy, source)
|
||||
self.assertRaises(OSError, source.copy, source, follow_symlinks=False)
|
||||
|
||||
def test_copy_dir(self):
|
||||
source = self.source_root / 'dirC'
|
||||
target = self.target_root / 'copyC'
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isdir(target))
|
||||
self.assertTrue(self.target_ground.isfile(target / 'fileC'))
|
||||
self.assertEqual(self.target_ground.readtext(target / 'fileC'), 'this is file C\n')
|
||||
self.assertTrue(self.target_ground.isdir(target / 'dirD'))
|
||||
self.assertTrue(self.target_ground.isfile(target / 'dirD' / 'fileD'))
|
||||
self.assertEqual(self.target_ground.readtext(target / 'dirD' / 'fileD'), 'this is file D\n')
|
||||
|
||||
def test_copy_dir_follow_symlinks_true(self):
|
||||
if not self.source_ground.can_symlink:
|
||||
self.skipTest('needs symlink support on source')
|
||||
source = self.source_root / 'dirC'
|
||||
target = self.target_root / 'copyC'
|
||||
self.source_ground.create_symlink(source / 'linkC', 'fileC')
|
||||
self.source_ground.create_symlink(source / 'linkD', 'dirD')
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isdir(target))
|
||||
self.assertFalse(self.target_ground.islink(target / 'linkC'))
|
||||
self.assertTrue(self.target_ground.isfile(target / 'linkC'))
|
||||
self.assertEqual(self.target_ground.readtext(target / 'linkC'), 'this is file C\n')
|
||||
self.assertFalse(self.target_ground.islink(target / 'linkD'))
|
||||
self.assertTrue(self.target_ground.isdir(target / 'linkD'))
|
||||
self.assertTrue(self.target_ground.isfile(target / 'linkD' / 'fileD'))
|
||||
self.assertEqual(self.target_ground.readtext(target / 'linkD' / 'fileD'), 'this is file D\n')
|
||||
|
||||
def test_copy_dir_follow_symlinks_false(self):
|
||||
if not self.source_ground.can_symlink:
|
||||
self.skipTest('needs symlink support on source')
|
||||
if not self.target_ground.can_symlink:
|
||||
self.skipTest('needs symlink support on target')
|
||||
source = self.source_root / 'dirC'
|
||||
target = self.target_root / 'copyC'
|
||||
self.source_ground.create_symlink(source / 'linkC', 'fileC')
|
||||
self.source_ground.create_symlink(source / 'linkD', 'dirD')
|
||||
result = source.copy(target, follow_symlinks=False)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(self.target_ground.isdir(target))
|
||||
self.assertTrue(self.target_ground.islink(target / 'linkC'))
|
||||
self.assertEqual(self.target_ground.readlink(target / 'linkC'), 'fileC')
|
||||
self.assertTrue(self.target_ground.islink(target / 'linkD'))
|
||||
self.assertEqual(self.target_ground.readlink(target / 'linkD'), 'dirD')
|
||||
|
||||
def test_copy_dir_to_existing_directory(self):
|
||||
if not isinstance(self.target_root, WritableLocalPath):
|
||||
self.skipTest('needs local target')
|
||||
source = self.source_root / 'dirC'
|
||||
target = self.target_root / 'copyC'
|
||||
self.target_ground.create_dir(target)
|
||||
self.assertRaises(FileExistsError, source.copy, target)
|
||||
|
||||
def test_copy_dir_to_itself(self):
|
||||
source = self.source_root / 'dirC'
|
||||
self.assertRaises(OSError, source.copy, source)
|
||||
self.assertRaises(OSError, source.copy, source, follow_symlinks=False)
|
||||
|
||||
def test_copy_dir_into_itself(self):
|
||||
source = self.source_root / 'dirC'
|
||||
target = self.source_root / 'dirC' / 'dirD' / 'copyC'
|
||||
self.assertRaises(OSError, source.copy, target)
|
||||
self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
|
||||
|
||||
def test_copy_into(self):
|
||||
source = self.source_root / 'fileA'
|
||||
target_dir = self.target_root / 'dirA'
|
||||
self.target_ground.create_dir(target_dir)
|
||||
result = source.copy_into(target_dir)
|
||||
self.assertEqual(result, target_dir / 'fileA')
|
||||
self.assertTrue(self.target_ground.isfile(result))
|
||||
self.assertEqual(self.source_ground.readbytes(source),
|
||||
self.target_ground.readbytes(result))
|
||||
|
||||
def test_copy_into_empty_name(self):
|
||||
source = self.source_root.with_segments()
|
||||
target_dir = self.target_root / 'dirA'
|
||||
self.target_ground.create_dir(target_dir)
|
||||
self.assertRaises(ValueError, source.copy_into, target_dir)
|
||||
|
||||
|
||||
class ZipToZipPathCopyTest(CopyTestBase, unittest.TestCase):
|
||||
source_ground = ZipPathGround(ReadableZipPath)
|
||||
target_ground = ZipPathGround(WritableZipPath)
|
||||
|
||||
|
||||
class ZipToLocalPathCopyTest(CopyTestBase, unittest.TestCase):
|
||||
source_ground = ZipPathGround(ReadableZipPath)
|
||||
target_ground = LocalPathGround(Path)
|
||||
|
||||
|
||||
class LocalToZipPathCopyTest(CopyTestBase, unittest.TestCase):
|
||||
source_ground = LocalPathGround(Path)
|
||||
target_ground = ZipPathGround(WritableZipPath)
|
||||
|
||||
|
||||
class LocalToLocalPathCopyTest(CopyTestBase, unittest.TestCase):
|
||||
source_ground = LocalPathGround(Path)
|
||||
target_ground = LocalPathGround(Path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -343,144 +343,6 @@ class RWPathTest(WritablePathTest, ReadablePathTest):
|
|||
cls = DummyRWPath
|
||||
can_symlink = False
|
||||
|
||||
def test_copy_file(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'fileA'
|
||||
target = base / 'copyA'
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(result.info.exists())
|
||||
self.assertEqual(source.read_text(), result.read_text())
|
||||
|
||||
def test_copy_file_to_existing_file(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'fileA'
|
||||
target = base / 'dirB' / 'fileB'
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(result.info.exists())
|
||||
self.assertEqual(source.read_text(), result.read_text())
|
||||
|
||||
def test_copy_file_to_existing_directory(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'fileA'
|
||||
target = base / 'dirA'
|
||||
self.assertRaises(OSError, source.copy, target)
|
||||
|
||||
def test_copy_file_empty(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'empty'
|
||||
target = base / 'copyA'
|
||||
source.write_bytes(b'')
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(result.info.exists())
|
||||
self.assertEqual(result.read_bytes(), b'')
|
||||
|
||||
def test_copy_file_to_itself(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'empty'
|
||||
source.write_bytes(b'')
|
||||
self.assertRaises(OSError, source.copy, source)
|
||||
self.assertRaises(OSError, source.copy, source, follow_symlinks=False)
|
||||
|
||||
def test_copy_dir_simple(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'dirC'
|
||||
target = base / 'copyC'
|
||||
result = source.copy(target)
|
||||
self.assertEqual(result, target)
|
||||
self.assertTrue(result.info.is_dir())
|
||||
self.assertTrue(result.joinpath('dirD').info.is_dir())
|
||||
self.assertTrue(result.joinpath('dirD', 'fileD').info.is_file())
|
||||
self.assertEqual(result.joinpath('dirD', 'fileD').read_text(),
|
||||
"this is file D\n")
|
||||
self.assertTrue(result.joinpath('fileC').info.is_file())
|
||||
self.assertTrue(result.joinpath('fileC').read_text(),
|
||||
"this is file C\n")
|
||||
|
||||
def test_copy_dir_complex(self, follow_symlinks=True):
|
||||
def ordered_walk(path):
|
||||
for dirpath, dirnames, filenames in path.walk(follow_symlinks=follow_symlinks):
|
||||
dirnames.sort()
|
||||
filenames.sort()
|
||||
yield dirpath, dirnames, filenames
|
||||
base = self.cls(self.base)
|
||||
source = base / 'dirC'
|
||||
|
||||
if self.can_symlink:
|
||||
# Add some symlinks
|
||||
source.joinpath('linkC').symlink_to('fileC')
|
||||
source.joinpath('linkD').symlink_to('dirD', target_is_directory=True)
|
||||
|
||||
# Perform the copy
|
||||
target = base / 'copyC'
|
||||
result = source.copy(target, follow_symlinks=follow_symlinks)
|
||||
self.assertEqual(result, target)
|
||||
|
||||
# Compare the source and target trees
|
||||
source_walk = ordered_walk(source)
|
||||
target_walk = ordered_walk(result)
|
||||
for source_item, target_item in zip(source_walk, target_walk, strict=True):
|
||||
self.assertEqual(source_item[0].parts[len(source.parts):],
|
||||
target_item[0].parts[len(target.parts):]) # dirpath
|
||||
self.assertEqual(source_item[1], target_item[1]) # dirnames
|
||||
self.assertEqual(source_item[2], target_item[2]) # filenames
|
||||
# Compare files and symlinks
|
||||
for filename in source_item[2]:
|
||||
source_file = source_item[0].joinpath(filename)
|
||||
target_file = target_item[0].joinpath(filename)
|
||||
if follow_symlinks or not source_file.info.is_symlink():
|
||||
# Regular file.
|
||||
self.assertEqual(source_file.read_bytes(), target_file.read_bytes())
|
||||
elif source_file.info.is_dir():
|
||||
# Symlink to directory.
|
||||
self.assertTrue(target_file.info.is_dir())
|
||||
self.assertEqual(source_file.readlink(), target_file.readlink())
|
||||
else:
|
||||
# Symlink to file.
|
||||
self.assertEqual(source_file.read_bytes(), target_file.read_bytes())
|
||||
self.assertEqual(source_file.readlink(), target_file.readlink())
|
||||
|
||||
def test_copy_dir_complex_follow_symlinks_false(self):
|
||||
self.test_copy_dir_complex(follow_symlinks=False)
|
||||
|
||||
def test_copy_dir_to_existing_directory(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'dirC'
|
||||
target = base / 'copyC'
|
||||
target.mkdir()
|
||||
target.joinpath('dirD').mkdir()
|
||||
self.assertRaises(FileExistsError, source.copy, target)
|
||||
|
||||
def test_copy_dir_to_itself(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'dirC'
|
||||
self.assertRaises(OSError, source.copy, source)
|
||||
self.assertRaises(OSError, source.copy, source, follow_symlinks=False)
|
||||
|
||||
def test_copy_dir_into_itself(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'dirC'
|
||||
target = base / 'dirC' / 'dirD' / 'copyC'
|
||||
self.assertRaises(OSError, source.copy, target)
|
||||
self.assertRaises(OSError, source.copy, target, follow_symlinks=False)
|
||||
self.assertFalse(target.info.exists())
|
||||
|
||||
def test_copy_into(self):
|
||||
base = self.cls(self.base)
|
||||
source = base / 'fileA'
|
||||
target_dir = base / 'dirA'
|
||||
result = source.copy_into(target_dir)
|
||||
self.assertEqual(result, target_dir / 'fileA')
|
||||
self.assertTrue(result.info.exists())
|
||||
self.assertEqual(source.read_text(), result.read_text())
|
||||
|
||||
def test_copy_into_empty_name(self):
|
||||
source = self.cls('')
|
||||
target_dir = self.base
|
||||
self.assertRaises(ValueError, source.copy_into, target_dir)
|
||||
|
||||
|
||||
class ReadablePathWalkTest(unittest.TestCase):
|
||||
cls = DummyReadablePath
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue