Compare commits

..
3 changed files with 167 additions and 71 deletions
+28
View File
@@ -4,6 +4,7 @@ from sqlalchemy.orm import sessionmaker
from pilgrim.database import Base from pilgrim.database import Base
from pilgrim.models.travel_diary import TravelDiary from pilgrim.models.travel_diary import TravelDiary
from pilgrim.models.photo import Photo
# Todos os imports necessários para as fixtures devem estar aqui # Todos os imports necessários para as fixtures devem estar aqui
# ... # ...
@@ -34,3 +35,30 @@ def session_with_one_diary(db_session):
db_session.commit() db_session.commit()
db_session.refresh(diary) db_session.refresh(diary)
return db_session, diary return db_session, diary
@pytest.fixture
def session_with_photos(session_with_one_diary):
session, diary = session_with_one_diary
# Usamos a mesma raiz de diretório que o mock do teste espera
diaries_root = "/fake/diaries_root"
photo1 = Photo(
# CORREÇÃO: O caminho agora inclui a raiz e a subpasta 'images'
filepath=f"{diaries_root}/{diary.directory_name}/images/p1.jpg",
name="Foto 1",
photo_hash="hash1",
fk_travel_diary_id=diary.id
)
photo2 = Photo(
filepath=f"{diaries_root}/{diary.directory_name}/images/p2.jpg",
name="Foto 2",
photo_hash="hash2",
fk_travel_diary_id=diary.id
)
session.add_all([photo1, photo2])
session.commit()
return session, [photo1, photo2]
+139
View File
@@ -0,0 +1,139 @@
import pytest
from pathlib import Path
from pilgrim.service.photo_service import PhotoService
import hashlib
from unittest.mock import patch
from pilgrim.models.photo import Photo
from pilgrim.utils import DirectoryManager
@patch.object(PhotoService, '_copy_photo_to_diary')
@patch.object(PhotoService, 'hash_file', return_value="fake_hash_123")
def test_create_photo_successfully(mock_hash, mock_copy, session_with_one_diary):
session, diary = session_with_one_diary
service = PhotoService(session)
fake_source_path = Path("/path/original/imagem.jpg")
fake_copied_path = Path(f"~/.pilgrim/diaries/{diary.directory_name}/images/imagem.jpg")
mock_copy.return_value = fake_copied_path
new_photo = service.create(
filepath=fake_source_path,
name="Foto da Praia",
travel_diary_id=diary.id,
caption="Pôr do sol")
mock_hash.assert_called_once_with(fake_source_path)
mock_copy.assert_called_once_with(fake_source_path, diary)
assert new_photo is not None
assert new_photo.name == "Foto da Praia"
assert new_photo.photo_hash == "fake_hash_123"
assert new_photo.filepath == str(fake_copied_path)
def test_hash_file_generates_correct_hash(tmp_path: Path):
original_content_bytes = b"um conteudo de teste para o hash"
file_on_disk = tmp_path / "test.jpg"
file_on_disk.write_bytes(original_content_bytes)
hash_from_file = PhotoService.hash_file(file_on_disk)
expected_hash_func = hashlib.new('sha3_384')
expected_hash_func.update(original_content_bytes)
hash_from_memory = expected_hash_func.hexdigest()
assert hash_from_file == hash_from_memory
@patch.object(PhotoService, '_copy_photo_to_diary')
@patch.object(PhotoService, 'hash_file', return_value="hash_ja_existente")
def test_create_photo_returns_none_if_hash_exists(mock_hash, mock_copy, session_with_one_diary):
session, diary = session_with_one_diary
existing_photo = Photo(
filepath="/path/existente.jpg", name="Foto Antiga",
photo_hash="hash_ja_existente", fk_travel_diary_id=diary.id
)
session.add(existing_photo)
session.commit()
service = PhotoService(session)
new_photo = service.create(
filepath=Path("/path/novo/arquivo.jpg"),
name="Foto Nova",
travel_diary_id=diary.id
)
assert new_photo is None
mock_copy.assert_not_called()
def test_read_by_id_successfully(session_with_photos):
session, photos = session_with_photos
service = PhotoService(session)
photo_to_find_id = photos[0].id
found_photo = service.read_by_id(photo_to_find_id)
assert found_photo is not None
assert found_photo.id == photo_to_find_id
assert found_photo.name == "Foto 1"
def test_read_by_id_returns_none_for_invalid_id(db_session):
service = PhotoService(db_session)
result = service.read_by_id(999)
assert result is None
def test_read_all_returns_all_photos(session_with_photos):
session, _ = session_with_photos
service = PhotoService(session)
all_photos = service.read_all()
assert isinstance(all_photos, list)
assert len(all_photos) == 2
assert all_photos[0].name == "Foto 1"
assert all_photos[1].name == "Foto 2"
def test_read_all_returns_empty_list_for_empty_db(db_session):
service = PhotoService(db_session)
all_photos = service.read_all()
assert isinstance(all_photos, list)
assert len(all_photos) == 0
def test_check_photo_by_hash_finds_existing_photo(session_with_photos):
session, photos = session_with_photos
service = PhotoService(session)
existing_photo = photos[0]
hash_to_find = existing_photo.photo_hash # "hash1"
diary_id = existing_photo.fk_travel_diary_id # 1
found_photo = service.check_photo_by_hash(hash_to_find, diary_id)
assert found_photo is not None
assert found_photo.id == existing_photo.id
assert found_photo.photo_hash == hash_to_find
def test_check_photo_by_hash_returns_none_when_not_found(session_with_photos):
session, photos = session_with_photos
service = PhotoService(session)
existing_hash = photos[0].photo_hash # "hash1"
existing_diary_id = photos[0].fk_travel_diary_id # 1
result1 = service.check_photo_by_hash("hash_inexistente", existing_diary_id)
assert result1 is None
invalid_diary_id = 999
result2 = service.check_photo_by_hash(existing_hash, invalid_diary_id)
assert result2 is None
@patch('pathlib.Path.unlink')
@patch('pathlib.Path.exists')
@patch.object(DirectoryManager, 'get_diaries_root', return_value="/fake/diaries_root")
def test_delete_photo_successfully(mock_get_root, mock_exists, mock_unlink, session_with_photos):
session, photos = session_with_photos
service = PhotoService(session)
photo_to_delete = photos[0]
photo_id = photo_to_delete.id
mock_exists.return_value = True
deleted_photo_data = service.delete(photo_to_delete)
mock_unlink.assert_called_once()
assert deleted_photo_data is not None
assert deleted_photo_data.id == photo_id
photo_in_db = service.read_by_id(photo_id)
assert photo_in_db is None
@patch('pathlib.Path.unlink')
def test_delete_returns_none_for_non_existent_photo(mock_unlink, db_session):
service = PhotoService(db_session)
non_existent_photo = Photo(
filepath="/fake/path.jpg", name="dummy",
photo_hash="dummy_hash", fk_travel_diary_id=1
)
non_existent_photo.id = 999
result = service.delete(non_existent_photo)
assert result is None
mock_unlink.assert_not_called()
-71
View File
@@ -1,71 +0,0 @@
import shutil
from pathlib import Path
from unittest.mock import patch
import pytest
from pilgrim.utils.directory_manager import DirectoryManager
@patch('os.chmod')
@patch('pathlib.Path.home')
def test_get_config_directory_creates_dir_in_fake_home(mock_home, mock_chmod, tmp_path: Path):
mock_home.return_value = tmp_path
expected_config_dir = tmp_path / ".pilgrim"
assert not expected_config_dir.exists()
result_path = DirectoryManager.get_config_directory()
assert result_path == expected_config_dir
assert expected_config_dir.exists()
mock_chmod.assert_called_once_with(expected_config_dir, 0o700)
@patch('shutil.copy2')
@patch('pathlib.Path.home')
def test_get_database_path_no_migration(mock_home, mock_copy, tmp_path: Path):
mock_home.return_value = tmp_path
expected_db_path = tmp_path / ".pilgrim" / "database.db"
result_path = DirectoryManager.get_database_path()
assert result_path == expected_db_path
mock_copy.assert_not_called()
@patch('shutil.copy2')
@patch('pathlib.Path.home')
def test_get_database_path_with_migration(mock_home, mock_copy, tmp_path: Path, monkeypatch):
fake_home_dir = tmp_path / "home"
fake_project_dir = tmp_path / "project"
fake_home_dir.mkdir()
fake_project_dir.mkdir()
(fake_project_dir / "database.db").touch()
mock_home.return_value = fake_home_dir
monkeypatch.chdir(fake_project_dir)
result_path = DirectoryManager.get_database_path()
expected_db_path = fake_home_dir / ".pilgrim" / "database.db"
assert result_path == expected_db_path
mock_copy.assert_called_once_with(
Path("database.db"),
expected_db_path
)
@patch('os.chmod')
@patch('pathlib.Path.home')
def test_diary_path_methods_construct_correctly(mock_home, mock_chmod, tmp_path: Path):
mock_home.return_value = tmp_path
images_path = DirectoryManager.get_diary_images_directory("minha-viagem")
expected_path = tmp_path / ".pilgrim" / "diaries" / "minha-viagem" / "data" / "images"
assert images_path == expected_path
assert (tmp_path / ".pilgrim" / "diaries").exists()
@patch('shutil.copy2')
@patch('pathlib.Path.home')
def test_get_database_path_handles_migration_error(mock_home, mock_copy, tmp_path: Path, monkeypatch):
fake_home_dir = tmp_path / "home"
fake_project_dir = tmp_path / "project"
fake_home_dir.mkdir()
fake_project_dir.mkdir()
(fake_project_dir / "database.db").touch()
mock_home.return_value = fake_home_dir
mock_copy.side_effect = shutil.Error("O disco está cheio!")
monkeypatch.chdir(fake_project_dir)
with pytest.raises(RuntimeError, match="Failed to migrate database"):
DirectoryManager.get_database_path()
mock_copy.assert_called_once()