# encoding: utf-8 import pytest import codecs import os import sys from os import path as op from send2trash.compat import PY3 try: from configparser import ConfigParser except ImportError: # py2 from ConfigParser import ConfigParser 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) # Could still use cleaning up. But no longer relies on ramfs. # def touch(path): # with open(path, "a"): # os.utime(path, None) # class TestHomeTrash(unittest.TestCase): # def setUp(self): # self.file = NamedTemporaryFile( # dir=op.expanduser("~"), prefix="send2trash_test", delete=False # ) # def test_trash(self): # s2t(self.file.name) # self.assertFalse(op.exists(self.file.name)) # def tearDown(self): # name = op.basename(self.file.name) # os.remove(op.join(HOMETRASH, "files", name)) # os.remove(op.join(HOMETRASH, "info", name + ".trashinfo")) # class TestHomeMultiTrash(unittest.TestCase): # def setUp(self): # self.files = list( # map( # lambda index: NamedTemporaryFile( # dir=op.expanduser("~"), # prefix="send2trash_test{}".format(index), # delete=False, # ), # range(10), # ) # ) # def test_multitrash(self): # filenames = [file.name for file in self.files] # s2t(filenames) # self.assertFalse(any([op.exists(filename) for filename in filenames])) # def tearDown(self): # filenames = [op.basename(file.name) for file in self.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 _filesys_enc(): # enc = sys.getfilesystemencoding() # # Get canonical name of codec # return codecs.lookup(enc).name # @unittest.skipIf(_filesys_enc() == "ascii", "ASCII filesystem") # class TestUnicodeTrash(unittest.TestCase): # def setUp(self): # self.name = u"send2trash_tést1" # self.file = op.join(op.expanduser(b"~"), self.name.encode("utf-8")) # touch(self.file) # def test_trash_bytes(self): # s2t(self.file) # assert not op.exists(self.file) # def test_trash_unicode(self): # s2t(self.file.decode(sys.getfilesystemencoding())) # assert not op.exists(self.file) # def tearDown(self): # if op.exists(self.file): # os.remove(self.file) # trash_file = op.join(HOMETRASH, "files", self.name) # if op.exists(trash_file): # os.remove(trash_file) # os.remove(op.join(HOMETRASH, "info", self.name + ".trashinfo")) # # # # Tests for files on some other volume than the user's home directory. # # # # What we need to stub: # # * plat_other.get_dev (to make sure the file will not be on the home dir dev) # # * os.path.ismount (to make our topdir look like a top dir) # # # class TestExtVol(unittest.TestCase): # def setUp(self): # self.trashTopdir = mkdtemp(prefix="s2t") # if PY3: # trashTopdir_b = os.fsencode(self.trashTopdir) # else: # trashTopdir_b = self.trashTopdir # self.fileName = "test.txt" # self.filePath = op.join(self.trashTopdir, self.fileName) # touch(self.filePath) # self.old_ismount = old_ismount = op.ismount # self.old_getdev = send2trash.plat_other.get_dev # 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(trashTopdir_b), # ): # return True # return old_ismount(path) # send2trash.plat_other.os.path.ismount = s_ismount # send2trash.plat_other.get_dev = s_getdev # def tearDown(self): # send2trash.plat_other.get_dev = self.old_getdev # send2trash.plat_other.os.path.ismount = self.old_ismount # shutil.rmtree(self.trashTopdir) # class TestTopdirTrash(TestExtVol): # def setUp(self): # TestExtVol.setUp(self) # # Create a .Trash dir w/ a sticky bit # self.trashDir = op.join(self.trashTopdir, ".Trash") # os.mkdir(self.trashDir, 0o777 | stat.S_ISVTX) # def test_trash(self): # s2t(self.filePath) # self.assertFalse(op.exists(self.filePath)) # self.assertTrue( # op.exists(op.join(self.trashDir, str(os.getuid()), "files", self.fileName)) # ) # self.assertTrue( # op.exists( # op.join( # self.trashDir, # str(os.getuid()), # "info", # self.fileName + ".trashinfo", # ) # ) # ) # # info relative path (if another test is added, with the same fileName/Path, # # then it gets renamed etc.) # cfg = ConfigParser() # cfg.read( # op.join( # self.trashDir, str(os.getuid()), "info", self.fileName + ".trashinfo" # ) # ) # self.assertEqual(self.fileName, cfg.get("Trash Info", "Path", raw=True)) # # Test .Trash-UID # class TestTopdirTrashFallback(TestExtVol): # def test_trash(self): # touch(self.filePath) # s2t(self.filePath) # self.assertFalse(op.exists(self.filePath)) # self.assertTrue( # op.exists( # op.join( # self.trashTopdir, # ".Trash-" + str(os.getuid()), # "files", # self.fileName, # ) # ) # ) # # Test failure # class TestTopdirFailure(TestExtVol): # def setUp(self): # TestExtVol.setUp(self) # os.chmod(self.trashTopdir, 0o500) # not writable to induce the exception # def test_trash(self): # with self.assertRaises(OSError): # s2t(self.filePath) # self.assertTrue(op.exists(self.filePath)) # def tearDown(self): # os.chmod(self.trashTopdir, 0o700) # writable to allow deletion # TestExtVol.tearDown(self) # # Make sure it will find the mount point properly for a file in a symlinked path # class TestSymlink(TestExtVol): # def setUp(self): # TestExtVol.setUp(self) # # Use mktemp (race conditioney but no symlink equivalent) # # Since is_parent uses realpath(), and our getdev uses is_parent, # # this should work # self.slDir = mktemp(prefix="s2t", dir=op.expanduser("~")) # os.mkdir(op.join(self.trashTopdir, "subdir"), 0o700) # self.filePath = op.join(self.trashTopdir, "subdir", self.fileName) # touch(self.filePath) # os.symlink(op.join(self.trashTopdir, "subdir"), self.slDir) # def test_trash(self): # s2t(op.join(self.slDir, self.fileName)) # self.assertFalse(op.exists(self.filePath)) # self.assertTrue( # op.exists( # op.join( # self.trashTopdir, # ".Trash-" + str(os.getuid()), # "files", # self.fileName, # ) # ) # ) # def tearDown(self): # os.remove(self.slDir) # TestExtVol.tearDown(self)