/ tests / cli / test_cli_image_command.py
test_cli_image_command.py
  1  from pathlib import Path
  2  from unittest.mock import patch
  3  
  4  from cli import (
  5      HermesCLI,
  6      _collect_query_images,
  7      _format_image_attachment_badges,
  8      _termux_example_image_path,
  9  )
 10  
 11  
 12  def _make_cli():
 13      cli_obj = HermesCLI.__new__(HermesCLI)
 14      cli_obj._attached_images = []
 15      return cli_obj
 16  
 17  
 18  def _make_image(path: Path) -> Path:
 19      path.parent.mkdir(parents=True, exist_ok=True)
 20      path.write_bytes(b"\x89PNG\r\n\x1a\n")
 21      return path
 22  
 23  
 24  class TestImageCommand:
 25      def test_handle_image_command_attaches_local_image(self, tmp_path):
 26          img = _make_image(tmp_path / "photo.png")
 27          cli_obj = _make_cli()
 28  
 29          with patch("cli._cprint"):
 30              cli_obj._handle_image_command(f"/image {img}")
 31  
 32          assert cli_obj._attached_images == [img]
 33  
 34      def test_handle_image_command_supports_quoted_path_with_spaces(self, tmp_path):
 35          img = _make_image(tmp_path / "my photo.png")
 36          cli_obj = _make_cli()
 37  
 38          with patch("cli._cprint"):
 39              cli_obj._handle_image_command(f'/image "{img}"')
 40  
 41          assert cli_obj._attached_images == [img]
 42  
 43      def test_handle_image_command_rejects_non_image_file(self, tmp_path):
 44          file_path = tmp_path / "notes.txt"
 45          file_path.write_text("hello\n", encoding="utf-8")
 46          cli_obj = _make_cli()
 47  
 48          with patch("cli._cprint") as mock_print:
 49              cli_obj._handle_image_command(f"/image {file_path}")
 50  
 51          assert cli_obj._attached_images == []
 52          rendered = " ".join(str(arg) for call in mock_print.call_args_list for arg in call.args)
 53          assert "Not a supported image file" in rendered
 54  
 55  
 56  class TestCollectQueryImages:
 57      def test_collect_query_images_accepts_explicit_image_arg(self, tmp_path):
 58          img = _make_image(tmp_path / "diagram.png")
 59  
 60          message, images = _collect_query_images("describe this", str(img))
 61  
 62          assert message == "describe this"
 63          assert images == [img]
 64  
 65      def test_collect_query_images_extracts_leading_path(self, tmp_path):
 66          img = _make_image(tmp_path / "camera.png")
 67  
 68          message, images = _collect_query_images(f"{img} what do you see?")
 69  
 70          assert message == "what do you see?"
 71          assert images == [img]
 72  
 73      def test_collect_query_images_supports_tilde_paths(self, tmp_path, monkeypatch):
 74          home = tmp_path / "home"
 75          img = _make_image(home / "storage" / "shared" / "Pictures" / "cat.png")
 76          monkeypatch.setenv("HOME", str(home))
 77  
 78          message, images = _collect_query_images("describe this", "~/storage/shared/Pictures/cat.png")
 79  
 80          assert message == "describe this"
 81          assert images == [img]
 82  
 83  
 84  class TestTermuxImageHints:
 85      def test_termux_example_image_path_prefers_real_shared_storage_root(self, monkeypatch):
 86          existing = {"/sdcard", "/storage/emulated/0"}
 87          monkeypatch.setattr("cli.os.path.isdir", lambda path: path in existing)
 88  
 89          hint = _termux_example_image_path()
 90  
 91          assert hint == "/sdcard/Pictures/cat.png"
 92  
 93  
 94  class TestImageBadgeFormatting:
 95      def test_compact_badges_use_filename_on_narrow_terminals(self, tmp_path):
 96          img = _make_image(tmp_path / "Screenshot 2026-04-09 at 11.22.33 AM.png")
 97  
 98          badges = _format_image_attachment_badges([img], image_counter=1, width=40)
 99  
100          assert badges.startswith("[📎 ")
101          assert "Image #1" not in badges
102  
103      def test_compact_badges_summarize_multiple_images(self, tmp_path):
104          img1 = _make_image(tmp_path / "one.png")
105          img2 = _make_image(tmp_path / "two.png")
106  
107          badges = _format_image_attachment_badges([img1, img2], image_counter=2, width=45)
108  
109          assert badges == "[📎 2 images attached]"