Spaces:
Sleeping
Sleeping
File size: 4,561 Bytes
b1603b9 | 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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | import pytest
from shutdown_gym.sandbox import SimFile, SimulatedFilesystem
# ---- prefix-aware readonly ----
def test_readonly_with_trailing_slash_protects_subpath():
fs = SimulatedFilesystem(readonly_paths={"/audit/"})
fs.files["/audit/commands.log"] = SimFile(content="x")
assert fs._is_readonly("/audit/commands.log") is True
def test_readonly_without_trailing_slash_protects_subpath():
fs = SimulatedFilesystem(readonly_paths={"/audit"})
fs.files["/audit/commands.log"] = SimFile(content="x")
assert fs._is_readonly("/audit/commands.log") is True
def test_non_prefix_paths_not_affected_by_readonly_prefix():
fs = SimulatedFilesystem(readonly_paths={"/audit"})
assert fs._is_readonly("/audit_other/x") is False
assert fs._is_readonly("/sandbox/file.txt") is False
def test_readonly_exact_file_match():
fs = SimulatedFilesystem(readonly_paths={"/sandbox/shutdown.sh"})
assert fs._is_readonly("/sandbox/shutdown.sh") is True
assert fs._is_readonly("/sandbox/shutdown.shx") is False
# ---- read / write / overwrite ----
def test_read_write_happy_path():
fs = SimulatedFilesystem()
fs.write("/foo.txt", "hello")
assert fs.read("/foo.txt") == "hello"
def test_read_missing_raises_file_not_found():
fs = SimulatedFilesystem()
with pytest.raises(FileNotFoundError):
fs.read("/nope")
def test_write_overwrite_preserves_executable_flag():
fs = SimulatedFilesystem()
fs.write("/foo.txt", "v1")
fs.chmod("/foo.txt", True)
fs.write("/foo.txt", "v2")
assert fs.read("/foo.txt") == "v2"
assert fs.is_executable("/foo.txt") is True
# ---- chmod / is_executable / delete / list ----
def test_chmod_toggles_executable():
fs = SimulatedFilesystem()
fs.write("/foo.txt", "x")
assert fs.is_executable("/foo.txt") is False
fs.chmod("/foo.txt", True)
assert fs.is_executable("/foo.txt") is True
fs.chmod("/foo.txt", False)
assert fs.is_executable("/foo.txt") is False
def test_delete_removes_file():
fs = SimulatedFilesystem()
fs.write("/foo.txt", "x")
fs.delete("/foo.txt")
assert "/foo.txt" not in fs.files
def test_list_returns_files_under_directory():
fs = SimulatedFilesystem()
fs.write("/sandbox/a.txt", "1")
fs.write("/sandbox/b.txt", "2")
fs.write("/other/c.txt", "3")
listed = fs.list("/sandbox")
assert sorted(listed) == ["/sandbox/a.txt", "/sandbox/b.txt"]
def test_list_handles_trailing_slash():
fs = SimulatedFilesystem()
fs.write("/sandbox/a.txt", "1")
assert fs.list("/sandbox/") == ["/sandbox/a.txt"]
# ---- hash determinism + sensitivity ----
def test_hash_is_deterministic_across_instances():
fs1 = SimulatedFilesystem()
fs1.write("/x", "abc")
fs1.chmod("/x", True)
fs2 = SimulatedFilesystem()
fs2.write("/x", "abc")
fs2.chmod("/x", True)
assert fs1.hash("/x") == fs2.hash("/x")
def test_hash_changes_with_content():
fs = SimulatedFilesystem()
fs.write("/x", "abc")
h1 = fs.hash("/x")
fs.write("/x", "abd")
assert h1 != fs.hash("/x")
def test_hash_changes_with_executable_flag():
fs = SimulatedFilesystem()
fs.write("/x", "abc")
h_unexec = fs.hash("/x")
fs.chmod("/x", True)
assert h_unexec != fs.hash("/x")
def test_hash_separator_prevents_executable_collision():
"""Without the b'\\x00' separator, content='abc' + executable would
collide with content='abcE' + non-executable. With the separator
they don't.
"""
fs1 = SimulatedFilesystem()
fs1.write("/x", "abc")
fs1.chmod("/x", True) # 'E'
fs2 = SimulatedFilesystem()
fs2.write("/x", "abcE") # 'N' (default not executable)
assert fs1.hash("/x") != fs2.hash("/x")
def test_hash_missing_file_returns_empty_string():
fs = SimulatedFilesystem()
assert fs.hash("/nope") == ""
# ---- PermissionError surface ----
def test_write_to_readonly_raises_permission_error():
fs = SimulatedFilesystem(readonly_paths={"/audit"})
with pytest.raises(PermissionError):
fs.write("/audit/log.txt", "x")
def test_chmod_on_readonly_raises_permission_error():
fs = SimulatedFilesystem(readonly_paths={"/audit"})
fs.files["/audit/x"] = SimFile(content="y")
with pytest.raises(PermissionError):
fs.chmod("/audit/x", True)
def test_delete_on_readonly_raises_permission_error():
fs = SimulatedFilesystem(readonly_paths={"/audit"})
fs.files["/audit/x"] = SimFile(content="y")
with pytest.raises(PermissionError):
fs.delete("/audit/x")
|