|
| 1 | +import base64 |
| 2 | +import os |
| 3 | +import sys |
| 4 | + |
| 5 | +import pytest |
| 6 | + |
| 7 | + |
| 8 | +def test_urlsafe_b64decode_already_handles_crlf(): |
| 9 | + """Verify Python's urlsafe_b64decode ignores embedded CR/LF without manual stripping.""" |
| 10 | + original = b"Testdata" |
| 11 | + b64 = base64.urlsafe_b64encode(original).decode() |
| 12 | + |
| 13 | + assert base64.urlsafe_b64decode(b64 + "\n") == original |
| 14 | + assert base64.urlsafe_b64decode(b64[:4] + "\r\n" + b64[4:]) == original |
| 15 | + assert base64.urlsafe_b64decode(b64[:4] + "\r\r\n" + b64[4:]) == original |
| 16 | + |
| 17 | + |
| 18 | +def test_os_open_without_o_binary_corrupts_on_windows(tmp_path): |
| 19 | + """On Windows, os.open without O_BINARY translates LF to CRLF in written bytes.""" |
| 20 | + payload = b"\x89PNG\r\n\x1a\n" + b"\x00" * 50 |
| 21 | + |
| 22 | + tmp = str(tmp_path / "test_no_binary.bin") |
| 23 | + fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) |
| 24 | + try: |
| 25 | + os.write(fd, payload) |
| 26 | + finally: |
| 27 | + os.close(fd) |
| 28 | + |
| 29 | + with open(tmp, "rb") as f: |
| 30 | + written = f.read() |
| 31 | + |
| 32 | + if sys.platform == "win32": |
| 33 | + assert written != payload, "Expected corruption without O_BINARY on Windows" |
| 34 | + assert len(written) > len(payload) |
| 35 | + else: |
| 36 | + assert written == payload |
| 37 | + |
| 38 | + |
| 39 | +def test_os_open_with_o_binary_preserves_bytes(tmp_path): |
| 40 | + """os.open with O_BINARY writes binary data correctly on all platforms.""" |
| 41 | + payload = b"\x89PNG\r\n\x1a\n" + b"\x00" * 50 |
| 42 | + |
| 43 | + tmp = str(tmp_path / "test_with_binary.bin") |
| 44 | + flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC | getattr(os, 'O_BINARY', 0) |
| 45 | + |
| 46 | + fd = os.open(tmp, flags, 0o600) |
| 47 | + try: |
| 48 | + os.write(fd, payload) |
| 49 | + finally: |
| 50 | + os.close(fd) |
| 51 | + |
| 52 | + with open(tmp, "rb") as f: |
| 53 | + written = f.read() |
| 54 | + |
| 55 | + assert written == payload |
| 56 | + |
| 57 | + |
| 58 | +@pytest.fixture |
| 59 | +def isolated_storage(tmp_path, monkeypatch): |
| 60 | + """Create an AttachmentStorage that writes to a temp directory.""" |
| 61 | + import core.attachment_storage as storage_module |
| 62 | + monkeypatch.setattr(storage_module, "STORAGE_DIR", tmp_path) |
| 63 | + return storage_module.AttachmentStorage() |
| 64 | + |
| 65 | + |
| 66 | +def test_save_attachment_uses_binary_mode(isolated_storage): |
| 67 | + """Verify that AttachmentStorage.save_attachment writes files in binary mode.""" |
| 68 | + payload = b"\x89PNG\r\n\x1a\n" + b"\x00" * 100 |
| 69 | + b64_data = base64.urlsafe_b64encode(payload).decode() |
| 70 | + |
| 71 | + result = isolated_storage.save_attachment(b64_data, filename="test.png", mime_type="image/png") |
| 72 | + |
| 73 | + with open(result.path, "rb") as f: |
| 74 | + saved_bytes = f.read() |
| 75 | + |
| 76 | + assert saved_bytes == payload, ( |
| 77 | + f"Binary corruption detected: wrote {len(payload)} bytes, " |
| 78 | + f"read back {len(saved_bytes)} bytes" |
| 79 | + ) |
| 80 | + |
| 81 | + |
| 82 | +@pytest.mark.parametrize("payload", [ |
| 83 | + b"\x89PNG\r\n\x1a\n" + b"\xff" * 200, # PNG header |
| 84 | + b"%PDF-1.7\n" + b"\x00" * 200, # PDF header |
| 85 | + bytes(range(256)) * 4, # All byte values |
| 86 | +]) |
| 87 | +def test_save_attachment_preserves_various_binary_formats(isolated_storage, payload): |
| 88 | + """Ensure binary integrity for payloads containing LF/CR bytes.""" |
| 89 | + b64_data = base64.urlsafe_b64encode(payload).decode() |
| 90 | + result = isolated_storage.save_attachment(b64_data, filename="test.bin") |
| 91 | + |
| 92 | + with open(result.path, "rb") as f: |
| 93 | + saved_bytes = f.read() |
| 94 | + |
| 95 | + assert saved_bytes == payload |
0 commit comments