Repository navigation
Expand file tree
/
Copy pathutil_test.py
More file actions
84 lines (67 loc) · 3.12 KB
/
Copy pathutil_test.py
File metadata and controls
84 lines (67 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# SPDX-FileCopyrightText: Amutable GmbH <https://amutable.com/>
# SPDX-License-Identifier: MPL-2.0
"""Tests for the helpers tine's Python entry points share.
buck test tine//:test
"""
import stat
import tempfile
import unittest
from pathlib import Path
import util
def scratch(case: unittest.TestCase) -> Path:
tmp = tempfile.TemporaryDirectory(prefix="util-test.")
case.addCleanup(tmp.cleanup)
return Path(tmp.name)
class TestAtomicTextWriter(unittest.TestCase):
def test_keeps_the_mode_of_an_existing_file(self) -> None:
path = scratch(self) / "generated"
path.write_text("one\n")
path.chmod(0o600)
util.atomic_write_text(path, "two\n")
self.assertEqual(path.read_text(), "two\n")
self.assertEqual(stat.S_IMODE(path.stat().st_mode), 0o600)
def test_a_failed_write_leaves_no_trace(self) -> None:
root = scratch(self)
path = root / "generated"
path.write_text("one\n")
with self.assertRaises(RuntimeError), util.atomic_text_writer(path) as stream:
stream.write("two\n")
raise RuntimeError
self.assertEqual(path.read_text(), "one\n")
self.assertEqual([p.name for p in root.iterdir()], ["generated"])
class TestWriteIfChanged(unittest.TestCase):
def test_leaves_an_unchanged_file_alone(self) -> None:
path = scratch(self) / "generated"
util.write_if_changed(path, "one\n")
before = path.stat().st_mtime_ns
util.write_if_changed(path, "one\n")
self.assertEqual(path.stat().st_mtime_ns, before)
def test_replaces_a_changed_file(self) -> None:
path = scratch(self) / "generated"
util.write_if_changed(path, "one\n")
util.write_if_changed(path, "two\n")
self.assertEqual(path.read_text(), "two\n")
def test_a_file_reached_through_a_symlink_is_written_through(self) -> None:
# Buck reads that layout, and renaming over the link would leave the real file stale.
root = scratch(self)
shared = root / "shared.bcfg"
shared.write_text("one\n")
link = root / "generated"
link.symlink_to(shared)
util.write_if_changed(link, "two\n")
self.assertTrue(link.is_symlink())
self.assertEqual(shared.read_text(), "two\n")
def test_reports_a_path_it_cannot_write(self) -> None:
# Root, which the box runs as, writes through a read-only directory; an absent one stops it.
with self.assertRaisesRegex(SystemExit, "tine: cannot write"):
util.write_if_changed(scratch(self) / "absent" / "generated", "one\n")
class TestNamedFiles(unittest.TestCase):
def test_finds_nested_files_without_following_links(self) -> None:
source = scratch(self) / "source"
for directory in ("", "nested"):
(source / directory).mkdir(parents=True, exist_ok=True)
(source / directory / "wanted").touch()
(source / directory / "other").touch()
(source / "cycle").symlink_to(".")
(source / "dangling").symlink_to("missing")
self.assertEqual(util.named_files(source, "wanted"), [Path("nested/wanted"), Path("wanted")])