mirror of
https://github.com/arsenetar/send2trash.git
synced 2025-05-17 05:59:49 +00:00
Really just checking that the setup is able to create test files so it is known they were there then removed. Windows tests really need verification of recycle, which is not present.
236 lines
6.8 KiB
Python
236 lines
6.8 KiB
Python
# encoding: utf-8
|
|
import pytest
|
|
import codecs
|
|
import os
|
|
import sys
|
|
from os import path as op
|
|
from send2trash.compat import PY3
|
|
from send2trash import TrashPermissionError
|
|
|
|
try:
|
|
from configparser import ConfigParser
|
|
except ImportError:
|
|
# py2
|
|
from ConfigParser import ConfigParser # noqa: F401
|
|
|
|
from tempfile import mkdtemp, NamedTemporaryFile, mktemp
|
|
import shutil
|
|
import stat
|
|
|
|
if sys.platform != "win32":
|
|
import send2trash.plat_other
|
|
from send2trash.plat_other import send2trash as s2t
|
|
|
|
HOMETRASH = send2trash.plat_other.HOMETRASH
|
|
else:
|
|
pytest.skip("Skipping non-windows tests", allow_module_level=True)
|
|
|
|
|
|
@pytest.fixture
|
|
def testfile():
|
|
file = NamedTemporaryFile(
|
|
dir=op.expanduser("~"), prefix="send2trash_test", delete=False
|
|
)
|
|
file.close()
|
|
assert op.exists(file) is True
|
|
yield file
|
|
# Cleanup trash files on supported platforms
|
|
if sys.platform != "win32":
|
|
name = op.basename(file.name)
|
|
# Remove trash files if they exist
|
|
if op.exists(op.join(HOMETRASH, "files", name)):
|
|
os.remove(op.join(HOMETRASH, "files", name))
|
|
os.remove(op.join(HOMETRASH, "info", name + ".trashinfo"))
|
|
if op.exists(file.name):
|
|
os.remove(file.name)
|
|
|
|
|
|
@pytest.fixture
|
|
def testfiles():
|
|
files = list(
|
|
map(
|
|
lambda index: NamedTemporaryFile(
|
|
dir=op.expanduser("~"),
|
|
prefix="send2trash_test{}".format(index),
|
|
delete=False,
|
|
),
|
|
range(10),
|
|
)
|
|
)
|
|
[file.close() for file in files]
|
|
assert all([op.exists(file) for file in files]) is True
|
|
yield files
|
|
filenames = [op.basename(file.name) for file in files]
|
|
[os.remove(op.join(HOMETRASH, "files", filename)) for filename in filenames]
|
|
[
|
|
os.remove(op.join(HOMETRASH, "info", filename + ".trashinfo"))
|
|
for filename in filenames
|
|
]
|
|
|
|
|
|
def test_trash(testfile):
|
|
s2t(testfile.name)
|
|
assert op.exists(testfile.name) is False
|
|
|
|
|
|
def test_multitrash(testfiles):
|
|
filenames = [file.name for file in testfiles]
|
|
s2t(filenames)
|
|
assert any([op.exists(filename) for filename in filenames]) is False
|
|
|
|
|
|
def touch(path):
|
|
with open(path, "a"):
|
|
os.utime(path, None)
|
|
|
|
|
|
def _filesys_enc():
|
|
enc = sys.getfilesystemencoding()
|
|
# Get canonical name of codec
|
|
return codecs.lookup(enc).name
|
|
|
|
|
|
@pytest.fixture
|
|
def testUnicodefile():
|
|
name = u"send2trash_tést1"
|
|
file = op.join(op.expanduser(b"~"), name.encode("utf-8"))
|
|
touch(file)
|
|
assert op.exists(file) is True
|
|
yield file
|
|
# Cleanup trash files on supported platforms
|
|
if sys.platform != "win32":
|
|
# Remove trash files if they exist
|
|
if op.exists(op.join(HOMETRASH, "files", name)):
|
|
os.remove(op.join(HOMETRASH, "files", name))
|
|
os.remove(op.join(HOMETRASH, "info", name + ".trashinfo"))
|
|
if op.exists(file):
|
|
os.remove(file)
|
|
|
|
|
|
@pytest.mark.skipif(_filesys_enc() == "ascii", reason="Requires Unicode filesystem")
|
|
def test_trash_bytes(testUnicodefile):
|
|
s2t(testUnicodefile)
|
|
assert not op.exists(testUnicodefile)
|
|
|
|
|
|
@pytest.mark.skipif(_filesys_enc() == "ascii", reason="Requires Unicode filesystem")
|
|
def test_trash_unicode(testUnicodefile):
|
|
s2t(testUnicodefile.decode(sys.getfilesystemencoding()))
|
|
assert not op.exists(testUnicodefile)
|
|
|
|
|
|
class ExtVol:
|
|
def __init__(self, path):
|
|
self.trashTopdir = path
|
|
if PY3:
|
|
self.trashTopdir_b = os.fsencode(self.trashTopdir)
|
|
else:
|
|
self.trashTopdir_b = self.trashTopdir
|
|
|
|
def s_getdev(path):
|
|
from send2trash.plat_other import is_parent
|
|
|
|
st = os.lstat(path)
|
|
if is_parent(self.trashTopdir, path):
|
|
return "dev"
|
|
return st.st_dev
|
|
|
|
def s_ismount(path):
|
|
if op.realpath(path) in (
|
|
op.realpath(self.trashTopdir),
|
|
op.realpath(self.trashTopdir_b),
|
|
):
|
|
return True
|
|
return old_ismount(path)
|
|
|
|
self.old_ismount = old_ismount = op.ismount
|
|
self.old_getdev = send2trash.plat_other.get_dev
|
|
send2trash.plat_other.os.path.ismount = s_ismount
|
|
send2trash.plat_other.get_dev = s_getdev
|
|
|
|
def cleanup(self):
|
|
send2trash.plat_other.get_dev = self.old_getdev
|
|
send2trash.plat_other.os.path.ismount = self.old_ismount
|
|
shutil.rmtree(self.trashTopdir)
|
|
|
|
|
|
@pytest.fixture
|
|
def testExtVol():
|
|
trashTopdir = mkdtemp(prefix="s2t")
|
|
volume = ExtVol(trashTopdir)
|
|
fileName = "test.txt"
|
|
filePath = op.join(volume.trashTopdir, fileName)
|
|
touch(filePath)
|
|
assert op.exists(filePath) is True
|
|
yield volume, fileName, filePath
|
|
volume.cleanup()
|
|
|
|
|
|
def test_trash_topdir(testExtVol):
|
|
trashDir = op.join(testExtVol[0].trashTopdir, ".Trash")
|
|
os.mkdir(trashDir, 0o777 | stat.S_ISVTX)
|
|
|
|
s2t(testExtVol[2])
|
|
assert op.exists(testExtVol[2]) is False
|
|
assert (
|
|
op.exists(op.join(trashDir, str(os.getuid()), "files", testExtVol[1])) is True
|
|
)
|
|
assert (
|
|
op.exists(
|
|
op.join(trashDir, str(os.getuid()), "info", testExtVol[1] + ".trashinfo",)
|
|
)
|
|
is True
|
|
)
|
|
# info relative path (if another test is added, with the same fileName/Path,
|
|
# then it gets renamed etc.)
|
|
cfg = ConfigParser()
|
|
cfg.read(op.join(trashDir, str(os.getuid()), "info", testExtVol[1] + ".trashinfo"))
|
|
assert (testExtVol[1] == cfg.get("Trash Info", "Path", raw=True)) is True
|
|
|
|
|
|
def test_trash_topdir_fallback(testExtVol):
|
|
s2t(testExtVol[2])
|
|
assert op.exists(testExtVol[2]) is False
|
|
assert (
|
|
op.exists(
|
|
op.join(
|
|
testExtVol[0].trashTopdir,
|
|
".Trash-" + str(os.getuid()),
|
|
"files",
|
|
testExtVol[1],
|
|
)
|
|
)
|
|
is True
|
|
)
|
|
|
|
|
|
def test_trash_topdir_failure(testExtVol):
|
|
os.chmod(testExtVol[0].trashTopdir, 0o500) # not writable to induce the exception
|
|
pytest.raises(TrashPermissionError, s2t, [testExtVol[2]])
|
|
os.chmod(testExtVol[0].trashTopdir, 0o700) # writable to allow deletion
|
|
|
|
|
|
def test_trash_symlink(testExtVol):
|
|
# Use mktemp (race conditioney but no symlink equivalent)
|
|
# Since is_parent uses realpath(), and our getdev uses is_parent,
|
|
# this should work
|
|
slDir = mktemp(prefix="s2t", dir=op.expanduser("~"))
|
|
os.mkdir(op.join(testExtVol[0].trashTopdir, "subdir"), 0o700)
|
|
filePath = op.join(testExtVol[0].trashTopdir, "subdir", testExtVol[1])
|
|
touch(filePath)
|
|
os.symlink(op.join(testExtVol[0].trashTopdir, "subdir"), slDir)
|
|
s2t(op.join(slDir, testExtVol[1]))
|
|
assert op.exists(filePath) is False
|
|
assert (
|
|
op.exists(
|
|
op.join(
|
|
testExtVol[0].trashTopdir,
|
|
".Trash-" + str(os.getuid()),
|
|
"files",
|
|
testExtVol[1],
|
|
)
|
|
)
|
|
is True
|
|
)
|
|
os.remove(slDir)
|