Coverage for tests/test_file.py: 22%
94 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-13 09:44 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-13 09:44 +0000
1# This file is part of lsst-resources.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12import os
13import pathlib
14import unittest
15import unittest.mock
16import urllib.parse
18from lsst.resources import ResourcePath, ResourcePathExpression
19from lsst.resources.tests import GenericReadWriteTestCase, GenericTestCase
21TESTDIR = os.path.abspath(os.path.dirname(__file__))
24class SimpleTestCase(unittest.TestCase):
25 """Basic tests for file URIs."""
27 def test_instance(self):
28 for example in (
29 "xxx",
30 ResourcePath("xxx"),
31 pathlib.Path("xxx"),
32 urllib.parse.urlparse("file:///xxx"),
33 ):
34 self.assertIsInstance(example, ResourcePathExpression)
36 for example in ({1, 2, 3}, 42, self):
37 self.assertNotIsInstance(example, ResourcePathExpression)
40class FileTestCase(GenericTestCase, unittest.TestCase):
41 """File-specific generic test cases."""
43 scheme = "file"
44 netloc = "localhost"
46 def test_env_var(self):
47 """Test that environment variables are expanded."""
48 with unittest.mock.patch.dict(os.environ, {"MY_TEST_DIR": "/a/b/c"}):
49 uri = ResourcePath("${MY_TEST_DIR}/d.txt")
50 self.assertEqual(uri.path, "/a/b/c/d.txt")
51 self.assertEqual(uri.scheme, "file")
53 # This will not expand
54 uri = ResourcePath("${MY_TEST_DIR}/d.txt", forceAbsolute=False)
55 self.assertEqual(uri.path, "${MY_TEST_DIR}/d.txt")
56 self.assertFalse(uri.scheme)
58 def test_ospath(self):
59 """File URIs have ospath property."""
60 file = ResourcePath(self._make_uri("a/test.txt"))
61 self.assertEqual(file.ospath, "/a/test.txt")
62 self.assertEqual(file.ospath, file.path)
64 # A Schemeless URI can take unquoted files but will be quoted
65 # when it becomes a file URI.
66 something = "/a#/???.txt"
67 file = ResourcePath(something, forceAbsolute=True)
68 self.assertEqual(file.scheme, "file")
69 self.assertEqual(file.ospath, something, "From URI: {file}")
70 self.assertNotIn("???", file.path)
72 def test_path_lib(self):
73 """File URIs can be created from pathlib"""
74 file = ResourcePath(self._make_uri("a/test.txt"))
76 path_file = pathlib.Path(file.ospath)
77 from_path = ResourcePath(path_file)
78 self.assertEqual(from_path.ospath, file.ospath)
80 def test_schemeless_root(self):
81 root = ResourcePath(self._make_uri("/root"))
82 via_root = ResourcePath("b.txt", root=root)
83 self.assertEqual(via_root.ospath, "/root/b.txt")
86class FileReadWriteTestCase(GenericReadWriteTestCase, unittest.TestCase):
87 """File tests involving reading and writing of data."""
89 scheme = "file"
90 netloc = "localhost"
91 testdir = TESTDIR
92 transfer_modes = ("move", "copy", "link", "hardlink", "symlink", "relsymlink")
94 def test_transfer_identical(self):
95 """Test overwrite of identical files.
97 Only relevant for local files.
98 """
99 dir1 = self.tmpdir.join("dir1", forceDirectory=True)
100 dir1.mkdir()
101 self.assertTrue(dir1.exists())
102 dir2 = self.tmpdir.join("dir2", forceDirectory=True)
103 # A symlink can't include a trailing slash.
104 dir2_ospath = dir2.ospath
105 if dir2_ospath.endswith("/"):
106 dir2_ospath = dir2_ospath[:-1]
107 os.symlink(dir1.ospath, dir2_ospath)
109 # Write a test file.
110 src_file = dir1.join("test.txt")
111 content = "0123456"
112 src_file.write(content.encode())
114 # Construct URI to destination that should be identical.
115 dest_file = dir2.join("test.txt")
116 self.assertTrue(dest_file.exists())
117 self.assertNotEqual(src_file, dest_file)
119 # Transfer it over itself.
120 dest_file.transfer_from(src_file, transfer="symlink", overwrite=True)
121 new_content = dest_file.read().decode()
122 self.assertEqual(content, new_content)
124 def test_local_temporary(self):
125 """Create temporary local file if no prefix specified."""
126 with ResourcePath.temporary_uri(suffix=".json") as tmp:
127 self.assertEqual(tmp.getExtension(), ".json", f"uri: {tmp}")
128 self.assertTrue(tmp.isabs(), f"uri: {tmp}")
129 self.assertFalse(tmp.exists(), f"uri: {tmp}")
130 tmp.write(b"abcd")
131 self.assertTrue(tmp.exists(), f"uri: {tmp}")
132 self.assertTrue(tmp.isTemporary)
133 self.assertTrue(tmp.isLocal)
135 # If we now ask for a local form of this temporary file
136 # it should still be temporary and it should not be deleted
137 # on exit.
138 with tmp.as_local() as loc:
139 self.assertEqual(tmp, loc)
140 self.assertTrue(loc.isTemporary)
141 self.assertTrue(tmp.exists())
142 self.assertFalse(tmp.exists(), f"uri: {tmp}")
144 def test_transfers_from_local(self):
145 """Extra tests for local transfers."""
146 target = self.tmpdir.join("a/target.txt")
147 with ResourcePath.temporary_uri() as tmp:
148 tmp.write(b"")
149 self.assertTrue(tmp.isTemporary)
151 # Symlink transfers for temporary resources should
152 # trigger a debug message.
153 for transfer in ("symlink", "relsymlink"):
154 with self.assertLogs("lsst.resources", level="DEBUG") as cm:
155 target.transfer_from(tmp, transfer)
156 target.remove()
157 self.assertIn("Using a symlink for a temporary", "".join(cm.output))
159 # Force the target directory to be created.
160 target.transfer_from(tmp, "move")
161 self.assertFalse(tmp.exists())
163 # Temporary file now gone so transfer should not work.
164 with self.assertRaises(FileNotFoundError):
165 target.transfer_from(tmp, "move", overwrite=True)
168if __name__ == "__main__":
169 unittest.main()