Skip to content

Commit

Permalink
error add + move file/folder is_subdir test
Browse files Browse the repository at this point in the history
  • Loading branch information
dvorakj31 committed Feb 7, 2019
1 parent 24b0ee6 commit 98ae4cd
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 13 deletions.
4 changes: 4 additions & 0 deletions securefile_handler/errors.py
Expand Up @@ -26,6 +26,10 @@ class CannotReadFileError(Exception):
pass


class SameFileError(Exception):
pass


class SameDirectoryError(Exception):
pass

Expand Down
21 changes: 12 additions & 9 deletions securefile_handler/securefile_handler.py
Expand Up @@ -48,7 +48,7 @@ def remove_file(filepath: Union[str, Path], erase_function: callable = erase_hel
"""
if not _check_params([filepath]):
raise errors.WrongFilepathType(f'Wrong filepath type {type(filepath)}')
fpath = Path(filepath)
fpath = filepath if isinstance(filepath, Path) else Path(filepath)
if not fpath.is_file():
raise errors.NotAFileError(f'{filepath} is not a file')
if not callable(erase_function):
Expand Down Expand Up @@ -76,7 +76,7 @@ def remove_dirtree(dirpath: Union[str, Path], erase_function: callable = erase_h
raise errors.WrongFilepathType(f'Wrong dirpath type {type(dirpath)}')
if not callable(erase_function):
raise errors.EraseFunctionError('Erase function is not callable')
dir_path = Path(dirpath)
dir_path = dirpath if isinstance(dirpath, Path) else Path(dirpath)
if len(os.listdir(dir_path.absolute())) == 0:
raise errors.EmptyFolderError(f'Folder {dir_path.absolute()} is empty')
erase_helpers.remove_dirtree(dir_path, erase_function)
Expand All @@ -100,13 +100,14 @@ def move_folder(src_dir: Union[str, Path], dst_dir: Union[str, Path], erase_func
raise errors.WrongFilepathType(f'Wrong parameter type')
if not callable(erase_function):
raise errors.EraseFunctionError('Erase function is not callable')
src_path, dst_path = src_dir if isinstance(src_dir, Path) else Path(src_dir), dst_dir if isinstance(dst_dir, Path) \
else Path(dst_dir)
if not len(os.listdir(src_path.absolute())):
raise errors.EmptyFolderError(f'Folder {src_path.absolute()} is empty')
if _is_subdir(str(src_dir), str(dst_dir)):
raise errors.SubDirectoryError(f'Cannot move {dst_dir} subdirectory of {src_dir}')
src_path, dst_path = Path(src_dir), Path(dst_dir)
if src_path.stat().st_dev == dst_path.stat().st_dev:
raise errors.SameDriveError("Cannot move folder to same drive")
if len(os.listdir(src_path.absolute())) == 0:
raise errors.EmptyFolderError(f'Folder {src_path.absolute()} is empty')
shutil.copytree(src_path.resolve(), dst_path.resolve())
erase_helpers.remove_dirtree(src_path, erase_function)

Expand All @@ -127,14 +128,16 @@ def move_file(src: Union[str, Path], dst: Union[str, Path], erase_function: call
:param erase_function: Function for erasing data in files. This optional argument is a callable.
"""
if not _check_params([src, dst]):
raise errors.WrongFilepathType(f'Wrong parameter type')
raise errors.WrongFilepathType(f'Wrong parameter type {src} {dst}')
if not callable(erase_function):
raise errors.EraseFunctionError('Erase function is not callable')
src_path, dst_path = Path(src), Path(dst)
src_path, dst_path = src if isinstance(src, Path) else Path(src), dst if isinstance(dst, Path) else Path(dst)
if src_path.stat().st_dev == dst_path.stat().st_dev:
raise errors.SameDriveError("Cannot move file to same drive")
if not src_path.is_file() or src_path.is_symlink():
raise errors.NotAFileError(f'{src} is not a regular file')
if src_path.resolve() == dst_path.resolve():
raise errors.SameFileError(f'{src_path} is same file as {dst_path}')
if not src_path.is_file():
raise errors.NotAFileError(f'{src} is not a file')
shutil.copy2(src_path.absolute(), dst_path.absolute())
erase_function(src_path.resolve())
if src_path.is_symlink():
Expand Down
16 changes: 12 additions & 4 deletions tests/test_is_subdir.py
Expand Up @@ -5,11 +5,19 @@

def test_is_subdir():
assert _is_subdir('/', '/home')
assert not _is_subdir('/home', '/')
assert not _is_subdir('/a/b/c', '/a/b/')
assert not _is_subdir('/a/b/c', '/a/b/')
assert _is_subdir('/source', '/source/dest')
assert _is_subdir('/tmp/a/b/', '/tmp/a/b/c')
assert _is_subdir('/root', '/root/some_subdir')


def test_is_subdir_error():
with pytest.raises(SameDirectoryError):
assert _is_subdir('/', '/')
assert _is_subdir('~', '~')


def test_is_subdir_not():
assert not _is_subdir('/home', '/')
assert not _is_subdir('/a/b/c', '/a/b/')
assert not _is_subdir('/a/b/c', '/a/b/d')
assert not _is_subdir('/tmp', '/tmp2')
assert _is_subdir('/source', '/source/dest')
87 changes: 87 additions & 0 deletions tests/test_move_files.py
@@ -0,0 +1,87 @@
import pytest
from unittest.mock import MagicMock
from pathlib import Path
import os
import securefile_handler.securefile_handler
from securefile_handler import errors
import preparements


class FakePathObject:

_parts = ''

def stat(self):
raise NotImplementedError()

def absolute(self):
raise NotImplementedError()

def __fspath__(self):
raise NotImplementedError()


class FakeStat:
def __init__(self, st_dev):
self.st_dev = st_dev


def test_move_file_errors():
with pytest.raises(errors.WrongFilepathType):
securefile_handler.securefile_handler.move_file((',', ), 'str')
with pytest.raises(errors.EraseFunctionError):
securefile_handler.securefile_handler.move_file('correct/src', 'correct/dst', 'non-callable')
with pytest.raises(errors.SameDriveError):
securefile_handler.securefile_handler.move_file('/', '/',)
with pytest.raises(errors.SameFileError):
file_path = Path(preparements.prepare_empty_file())
attrs = {
'stat.return_value': FakeStat(file_path.stat().st_dev + 1),
'resolve': file_path.resolve
}
fake_file = MagicMock(spec=Path, wraps=FakePathObject, **attrs)
fake_file.__fspath__ = lambda: file_path.absolute()
securefile_handler.securefile_handler.move_file(fake_file, file_path)
preparements.delete_file(file_path)
with pytest.raises(errors.NotAFileError):
tmp_dir = Path(preparements.prepare_tmp_dir())
attrs = {
'stat.return_value': FakeStat(tmp_dir.stat().st_dev + 1),
'resolve': lambda: os.urandom(10)
}
fake_file = MagicMock(spec=Path, wraps=FakePathObject, **attrs)
fake_file.__fspath__ = lambda: file_path.absolute()
securefile_handler.securefile_handler.move_file(tmp_dir, fake_file)
tmp_dir.rmdir()


def test_move_folder_errors():
with pytest.raises(errors.WrongFilepathType):
securefile_handler.securefile_handler.move_folder((',', ), 'str')
with pytest.raises(errors.EraseFunctionError):
securefile_handler.securefile_handler.move_folder('correct/src', 'correct/dst', 'non-callable')
with pytest.raises(errors.EmptyFolderError):
tmp_dir = Path(preparements.prepare_tmp_dir())
securefile_handler.move_folder(tmp_dir, tmp_dir)
tmp_dir.rmdir()
with pytest.raises(errors.SameDirectoryError):
securefile_handler.securefile_handler.move_folder('/', '/')
with pytest.raises(errors.SubDirectoryError):
tmp_dir = Path(preparements.prepare_tmp_dir())
dst_dir = Path(preparements.prepare_tmp_dir(tmp_dir.resolve()))
securefile_handler.securefile_handler.move_folder(tmp_dir, dst_dir)
tmp = dst_dir
with pytest.raises(errors.SameDriveError):
dst_dir = Path(preparements.prepare_tmp_dir())
securefile_handler.securefile_handler.move_folder(tmp_dir, dst_dir)
tmp.rmdir()
dst_dir.rmdir()
tmp_dir.rmdir()


def test_move_file():
...


def test_move_folder():
...

0 comments on commit 98ae4cd

Please sign in to comment.