diff --git a/reframe/utility/osext.py b/reframe/utility/osext.py index 5979e5ba0d..ad88957f51 100644 --- a/reframe/utility/osext.py +++ b/reframe/utility/osext.py @@ -156,7 +156,20 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=shutil.copy2, return shutil.copytree(src, dst, symlinks, ignore, copy_function, ignore_dangling_symlinks) - # dst exists; manually descend into the subdirectories + # dst exists; manually descend into the subdirectories, but do some sanity + # checking first + + # We raise the following errors to comply with the copytree()'s behaviour + + if not os.path.isdir(dst): + raise FileExistsError(errno.EEXIST, 'File exists', dst) + + if not os.path.exists(src): + raise FileNotFoundError(errno.ENOENT, 'No such file or directory', src) + + if not os.path.isdir(src): + raise NotADirectoryError(errno.ENOTDIR, 'Not a directory', src) + _, subdirs, files = list(os.walk(src))[0] ignore_paths = ignore(src, os.listdir(src)) if ignore else {} for f in files: diff --git a/unittests/test_utility.py b/unittests/test_utility.py index 2e8feec625..bfc7096958 100644 --- a/unittests/test_utility.py +++ b/unittests/test_utility.py @@ -80,6 +80,37 @@ def test_copytree_src_parent_of_dst(tmp_path): osext.copytree(str(src_path), str(dst_path)) +@pytest.fixture(params=['dirs_exist_ok=True', 'dirs_exist_ok=False']) +def dirs_exist_ok(request): + return 'True' in request.param + + +def test_copytree_dst_notdir(tmp_path, dirs_exist_ok): + dir_src = tmp_path / 'src' + dir_src.mkdir() + dst = tmp_path / 'dst' + dst.touch() + with pytest.raises(FileExistsError, match=fr'{dst}'): + osext.copytree(str(dir_src), str(dst), dirs_exist_ok=dirs_exist_ok) + + +def test_copytree_src_notdir(tmp_path, dirs_exist_ok): + src = tmp_path / 'src' + src.touch() + dst = tmp_path / 'dst' + dst.mkdir() + with pytest.raises(NotADirectoryError, match=fr'{src}'): + osext.copytree(str(src), str(dst), dirs_exist_ok=dirs_exist_ok) + + +def test_copytree_src_does_not_exist(tmp_path, dirs_exist_ok): + src = tmp_path / 'src' + dst = tmp_path / 'dst' + dst.mkdir() + with pytest.raises(FileNotFoundError, match=fr'{src}'): + osext.copytree(str(src), str(dst), dirs_exist_ok=dirs_exist_ok) + + @pytest.fixture def rmtree(tmp_path): testdir = tmp_path / 'test'