|
5 | 5 | import hashlib |
6 | 6 | import json |
7 | 7 | import os |
| 8 | +import shutil |
8 | 9 | import sys |
9 | 10 | import tempfile |
10 | 11 | from pathlib import Path |
@@ -634,6 +635,55 @@ def test_multiple_shift_enters(self): |
634 | 635 | assert "A \nB \nC" in out |
635 | 636 |
|
636 | 637 |
|
| 638 | +# ── 이미지 재다운로드: Notion 이미지 교체 시 같은 index 파일 덮어쓰기 ────────── |
| 639 | + |
| 640 | +class TestDownloadImageRedownload: |
| 641 | + """Notion에서 이미지를 교체하면 URL은 바뀌지만 img-NN 파일명은 동일하다. |
| 642 | + 파일이 존재해도 새 내용이면 덮어써야 stale 이미지가 남지 않는다.""" |
| 643 | + |
| 644 | + def setup_method(self): |
| 645 | + self.tmpdir = tempfile.mkdtemp() |
| 646 | + self._orig = n.STATIC_IMG_DIR |
| 647 | + n.STATIC_IMG_DIR = self.tmpdir |
| 648 | + |
| 649 | + def teardown_method(self): |
| 650 | + n.STATIC_IMG_DIR = self._orig |
| 651 | + shutil.rmtree(self.tmpdir, ignore_errors=True) |
| 652 | + |
| 653 | + def _mock_response(self, content): |
| 654 | + m = MagicMock() |
| 655 | + m.content = content |
| 656 | + m.raise_for_status = lambda: None |
| 657 | + return m |
| 658 | + |
| 659 | + def _prewrite(self, content): |
| 660 | + save_dir = os.path.join(self.tmpdir, "blog", "x") |
| 661 | + os.makedirs(save_dir, exist_ok=True) |
| 662 | + path = os.path.join(save_dir, "img-00.png") |
| 663 | + with open(path, "wb") as f: |
| 664 | + f.write(content) |
| 665 | + return path |
| 666 | + |
| 667 | + @patch.object(n, "requests") |
| 668 | + def test_overwrites_when_content_changed(self, mock_requests): |
| 669 | + path = self._prewrite(b"OLD-IMAGE") |
| 670 | + mock_requests.get.return_value = self._mock_response(b"NEW-IMAGE") |
| 671 | + n.download_image("https://notion/new.png", "blog/x", 0) |
| 672 | + with open(path, "rb") as f: |
| 673 | + assert f.read() == b"NEW-IMAGE" |
| 674 | + |
| 675 | + @patch.object(n, "requests") |
| 676 | + def test_no_rewrite_when_identical(self, mock_requests): |
| 677 | + # 내용 동일 시 재기록하지 않아 git churn 방지 (mtime 유지) |
| 678 | + path = self._prewrite(b"SAME-IMAGE") |
| 679 | + os.utime(path, (1_000_000, 1_000_000)) |
| 680 | + mock_requests.get.return_value = self._mock_response(b"SAME-IMAGE") |
| 681 | + n.download_image("https://notion/x.png", "blog/x", 0) |
| 682 | + assert os.path.getmtime(path) == 1_000_000 |
| 683 | + with open(path, "rb") as f: |
| 684 | + assert f.read() == b"SAME-IMAGE" |
| 685 | + |
| 686 | + |
637 | 687 | # ── 리스트 항목의 이미지 자식은 최상위(전체 폭)로 hoist ────────────────────── |
638 | 688 |
|
639 | 689 | class TestListItemImageHoisting: |
|
0 commit comments