from pathlib import Path from unittest.mock import patch import pytest from typer.testing import CliRunner from photools3.cli import app runner = CliRunner() @pytest.fixture def mock_photo_logic(tmp_path): """Fixture to mock the core logic of keywords command.""" with ( patch("photools3.cli.LlmSessionCaptionsAndKeywords") as mocked_session, patch("photools3.cli.Photo") as mocked_photo, ): # Configure session mock session_instance = mocked_session.return_value session_instance.call.return_value = { "caption": "A beautiful test image", "args": ["test", "mock", "image"], # Wait, the code uses 'tags' } # Let me re-check the code in cli.py # result.get("tags", []) session_instance.call.return_value = { "caption": "A beautiful test image", "tags": ["test", "mock", "image"], } # Configure photo mock photo_instance = mocked_photo.return_value photo_instance.path = tmp_path / "test_image.jpg" yield { "session": session_instance, "photo_class": mocked_photo, "photo_instance": photo_instance, } @pytest.fixture def dummy_file(tmp_path): """Fixture to create a dummy file for CLI testing.""" dummy_path = tmp_path / "test_image.jpg" dummy_path.write_text("dummy content") return dummy_path def test_keywords_command_success(mock_photo_logic, dummy_file): """Test the 'keywords' command with a valid file path.""" # Ensure the mock photo instance points to our dummy file mock_photo_logic["photo_class"].return_value.path = dummy_file result = runner.invoke(app, ["keywords", str(dummy_file)]) assert result.exit_code == 0 assert "Processing: " in result.stdout # The result is printed as a raw dictionary string assert ( "{'caption': 'A beautiful test image', 'tags': ['test', 'mock', 'image']}" in result.stdout ) def test_keywords_command_file_not_found(): """Test the 'keywords' command with a non-existent file path.""" non_existent_file = Path("non_existent_file.jpg") result = runner.invoke(app, ["keywords", str(non_existent_file)]) assert result.exit_code == 1 assert f"Error: File '{non_existent_file}' does not exist." in result.stderr def test_keywords_command_error_during_processing(mock_photo_logic, dummy_file): """Test the 'keywords' command when an exception occurs during processing.""" # Configure the session mock to raise an exception mock_photo_logic["session"].call.side_effect = Exception("LLM error") result = runner.invoke(app, ["keywords", str(dummy_file)]) assert result.exit_code == 1 assert "Error processing image: LLM error" in result.stderr def test_version_command(): """Test the --version option.""" result = runner.invoke(app, ["--version"]) assert result.exit_code == 0 assert "photools3 version 0.1.0" in result.stdout