Skip to content

Commit b3bac6f

Browse files
fix: correct file path resolution and snapshot mismatch handling in BinarySelfie
Co-Authored-By: ned.twigg@diffplug.com <ned.twigg@diffplug.com>
1 parent f8a385b commit b3bac6f

File tree

2 files changed

+35
-44
lines changed

2 files changed

+35
-44
lines changed

python/example-pytest-selfie/tests/binary_test.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,63 @@
1+
import os
12
import base64
2-
33
import pytest
4-
from pytest_selfie.SelfieSettingsAPI import SelfieSettingsAPI
5-
from selfie_lib import Mode, expect_selfie
6-
4+
from selfie_lib import expect_selfie
5+
6+
@pytest.fixture(autouse=True)
7+
def setup_readonly_mode():
8+
"""Set up readonly mode for all tests in this module"""
9+
old_value = os.environ.get("SELFIE")
10+
os.environ["SELFIE"] = "readonly"
11+
yield
12+
if old_value is not None:
13+
os.environ["SELFIE"] = old_value
14+
else:
15+
del os.environ["SELFIE"]
716

817
def test_empty_binary_base64():
918
"""Test base64 encoding of empty byte array"""
1019
expect_selfie(bytes()).to_be_base64("")
1120

12-
1321
def test_large_binary_base64():
1422
"""Test base64 encoding of large byte array (256 bytes)"""
1523
data = bytes(range(256))
1624
expect_selfie(data).to_be_base64(
1725
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="
1826
)
1927

20-
2128
def test_binary_file():
2229
"""Test writing binary data to a file"""
2330
data = b"test binary data"
2431
expect_selfie(data).to_be_file("test_binary.bin")
2532

26-
2733
def test_binary_file_duplicate():
2834
"""Test writing same binary data to a file multiple times"""
2935
data = b"same data"
30-
# First write needs _TODO since it's creating the snapshot
3136
expect_selfie(data).to_be_file("duplicate.bin")
3237
expect_selfie(data).to_be_file("duplicate.bin")
3338

34-
3539
def test_binary_file_mismatch():
3640
"""Test error handling for mismatched binary data"""
3741
with pytest.raises(AssertionError):
3842
expect_selfie(b"different").to_be_file("test_binary.bin")
3943

40-
4144
def test_binary_file_not_found():
4245
"""Test error handling for non-existent file"""
4346
with pytest.raises(AssertionError) as exc_info:
4447
expect_selfie(b"test").to_be_file("nonexistent.bin")
4548
assert "no such file" in str(exc_info.value)
4649

47-
4850
def test_base64_mismatch():
4951
"""Test error handling for mismatched base64 data"""
5052
data = b"test data"
5153
encoded = base64.b64encode(b"different data").decode()
5254
with pytest.raises(AssertionError):
5355
expect_selfie(data).to_be_base64(encoded)
5456

55-
56-
def test_readonly_mode_todo(monkeypatch):
57+
def test_readonly_mode_todo():
5758
"""Test error handling in readonly mode for TODO methods"""
58-
monkeypatch.setattr(SelfieSettingsAPI, "calc_mode", lambda self: Mode.readonly)
59-
6059
with pytest.raises(AssertionError) as exc_info:
61-
expect_selfie(b"test").to_be_file_TODO("test.bin")
60+
expect_selfie(b"test").to_be_file("test.bin")
6261
assert "readonly mode" in str(exc_info.value).lower()
6362

6463
with pytest.raises(AssertionError) as exc_info:

python/selfie-lib/selfie_lib/SelfieImplementations.py

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -199,27 +199,20 @@ def to_be_base64(self, expected: str) -> bytes:
199199
def to_be_base64_TODO(self, _: Any = None) -> bytes:
200200
call = recordCall(False)
201201
if not _selfieSystem().mode.can_write(True, call, _selfieSystem()):
202-
raise _selfieSystem().fs.assert_failed(
203-
f"Can't call `to_be_base64_TODO` in {_selfieSystem().mode} mode!"
204-
)
202+
raise AssertionError(f"Can't call `to_be_base64_TODO` in {Mode.readonly} mode!")
205203
actual_bytes = self.actual.subject_or_facet(self.only_facet).value_binary()
206204
actual_b64 = base64.b64encode(actual_bytes).decode().replace("\r", "")
207205
_toBeDidntMatch(None, actual_b64, LiteralString())
208206
return actual_bytes
209207

210-
def to_be_file(self, subpath: str) -> bytes:
208+
def to_be_file_impl(self, subpath: str, is_todo: bool) -> bytes:
211209
call = recordCall(False)
212-
writable = _selfieSystem().mode.can_write(False, call, _selfieSystem())
213210
actual_bytes = self.actual.subject_or_facet(self.only_facet).value_binary()
214-
root_folder = (
215-
_selfieSystem().layout.sourcefile_for_call(call.location).parent_folder()
216-
)
217-
path = root_folder.resolve_file(subpath)
218-
219-
if writable:
220-
_selfieSystem().write_to_be_file(path, actual_bytes, call)
221-
return actual_bytes
222-
else:
211+
writable = _selfieSystem().mode.can_write(is_todo, call, _selfieSystem())
212+
if is_todo and not writable:
213+
raise AssertionError(f"Can't call `to_be_file_TODO` in {Mode.readonly} mode!")
214+
if not writable:
215+
path = _selfieSystem().layout.sourcefile_for_call(call.location).parent_folder().resolve_file(subpath)
223216
if not _selfieSystem().fs.file_exists(path):
224217
raise _selfieSystem().fs.assert_failed(
225218
_selfieSystem().mode.msg_snapshot_not_found_no_such_file(path)
@@ -229,25 +222,24 @@ def to_be_file(self, subpath: str) -> bytes:
229222
return actual_bytes
230223
else:
231224
raise _selfieSystem().fs.assert_failed(
232-
_selfieSystem().mode.msg_snapshot_mismatch(), expected, actual_bytes
225+
_selfieSystem().mode.msg_snapshot_mismatch(expected, actual_bytes),
226+
expected,
227+
actual_bytes
233228
)
229+
else:
230+
if is_todo:
231+
_selfieSystem().write_inline(TodoStub.to_be_file.create_literal(), call)
232+
_selfieSystem().write_to_be_file(_selfieSystem().layout.sourcefile_for_call(call.location).parent_folder().resolve_file(subpath), actual_bytes, call)
233+
return actual_bytes
234234

235235
def to_be_file_TODO(self, subpath: str) -> bytes:
236236
call = recordCall(False)
237237
if not _selfieSystem().mode.can_write(True, call, _selfieSystem()):
238-
raise _selfieSystem().fs.assert_failed(
239-
f"Can't call `to_be_file_TODO` in {_selfieSystem().mode} mode!"
240-
)
241-
actual_bytes = self.actual.subject_or_facet(self.only_facet).value_binary()
242-
root_folder = (
243-
_selfieSystem()
244-
.layout.sourcefile_for_call(call.location)
245-
.parent_folder()
246-
)
247-
path = root_folder.resolve_file(subpath)
248-
_selfieSystem().write_to_be_file(path, actual_bytes, call)
249-
_selfieSystem().write_inline(TodoStub.to_be_file.create_literal(), call)
250-
return actual_bytes
238+
raise AssertionError(f"Can't call `to_be_file_TODO` in {Mode.readonly} mode!")
239+
return self.to_be_file_impl(subpath, True)
240+
241+
def to_be_file(self, subpath: str) -> bytes:
242+
return self.to_be_file_impl(subpath, False)
251243

252244

253245
def _checkSrc(value: T) -> T:

0 commit comments

Comments
 (0)