# pylint: disable=redefined-outer-name from dataclasses import dataclass from secrets import token_urlsafe from os.path import join from os import chdir, mkdir, symlink from pathlib import Path from tempfile import TemporaryDirectory import pytest from file_manager import FileManager @dataclass class ManagerContext: folder: str manager: FileManager def join(self, path): return join(self.folder, path) @pytest.fixture() def context(): dirs = {} with TemporaryDirectory() as workdir: chdir(workdir) for name in ['allowed', 'excluded', 'invis']: node = join(workdir, name) mkdir(node) Path(join(node, 'empty.txt')).touch() Path(join(node, 'empty.bin')).touch() dirs[name] = node yield ManagerContext( workdir, FileManager( dirs['allowed'], [dirs['allowed'], dirs['excluded']], exclude=['*/excluded/*'] ) ) @pytest.mark.parametrize('subdir', ['allowed/', 'excluded/']) def test_select_allowed_dirs(context, subdir): context.manager.workdir = context.join(subdir) assert context.manager.workdir == context.join(subdir) newdir = context.join(subdir+'deep') mkdir(newdir) context.manager.workdir = newdir assert context.manager.workdir == newdir @pytest.mark.parametrize('invdir', ['', 'invis']) def test_select_forbidden_dirs(context, invdir): fullpath = context.join(invdir) with pytest.raises(OSError): context.manager.workdir = fullpath assert context.manager.workdir != fullpath context.manager.allowed_directories += [fullpath] context.manager.workdir = fullpath assert context.manager.workdir == fullpath @pytest.mark.parametrize('filename', ['another.txt', '*.txt']) def test_select_allowed_files(context, filename): Path(context.join('allowed/'+filename)).touch() assert filename in context.manager.files context.manager.filename = filename assert context.manager.filename == filename @pytest.mark.parametrize('path', [ {'dir': 'allowed/', 'file': 'illegal.bin'}, {'dir': 'excluded/', 'file': 'legal.txt'}, {'dir': 'allowed/', 'file': token_urlsafe(16)+'.bin'}, {'dir': 'excluded/', 'file': token_urlsafe(16)+'.txt'}, {'dir': 'allowed/', 'file': token_urlsafe(32)+'.bin'}, {'dir': 'excluded/', 'file': token_urlsafe(32)+'.txt'} ]) def test_select_excluded_files(context, path): context.manager.workdir = context.join(path['dir']) context.manager.exclude = ['*/excluded/*', '*.bin'] Path(context.join(path['dir']+path['file'])).touch() assert path['file'] not in context.manager.files with pytest.raises(OSError): context.manager.filename = path['file'] @pytest.mark.parametrize('path', [ {'src': 'excluded/empty.txt', 'dst': 'allowed/link.txt'}, {'src': 'invis/empty.txt', 'dst': 'allowed/link.txt'}, {'src': 'excluded/empty.txt', 'dst': 'allowed/'+token_urlsafe(16)+'.txt'}, {'src': 'invis/empty.txt', 'dst': 'allowed/'+token_urlsafe(16)+'.txt'}, {'src': 'excluded/empty.txt', 'dst': 'allowed/'+token_urlsafe(32)+'.txt'}, {'src': 'invis/empty.txt', 'dst': 'allowed/'+token_urlsafe(32)+'.txt'} ]) def test_select_excluded_symlinks(context, path): symlink(context.join(path['src']), context.join(path['dst'])) assert path['dst'] not in context.manager.files def test_read_write_file(context): for _ in range(128): context.manager.filename = 'empty.txt' content = token_urlsafe(32) context.manager.file_contents = content assert context.manager.file_contents == content with open(context.join('allowed/empty.txt'), 'r') as ifile: assert ifile.read() == content def test_regular_ide_actions(context): context.manager.workdir = context.join('allowed') newfile1, newfile2 = token_urlsafe(16), token_urlsafe(16) Path(context.join(f'allowed/{newfile1}')).touch() Path(context.join(f'allowed/{newfile2}')).touch() for _ in range(8): context.manager.filename = newfile1 content1 = token_urlsafe(32) context.manager.file_contents = content1 context.manager.filename = newfile2 content2 = token_urlsafe(32) context.manager.file_contents = content2 context.manager.filename = newfile1 assert context.manager.file_contents == content1 context.manager.filename = newfile2 assert context.manager.file_contents == content2