From c4dceda9421fbb3510a1e093a0a8e8e562e138ee Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 03:35:22 -0300 Subject: [PATCH 1/7] test(entry_service): add unit test for creating a new entry This commit introduces the first unit test for the EntryService, covering the "happy path" for the `create` method. It verifies that a new entry is correctly persisted to the database, including its relationship with associated Photo objects. The test leverages fixtures to create an isolated, in-memory database populated with the necessary dependencies. --- tests/service/test_entry_service.py | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/service/test_entry_service.py diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py new file mode 100644 index 0000000..b2f1a6a --- /dev/null +++ b/tests/service/test_entry_service.py @@ -0,0 +1,55 @@ +import pytest +from datetime import datetime +from unittest.mock import Mock +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from pilgrim.database import Base +from pilgrim.models.travel_diary import TravelDiary +from pilgrim.models.entry import Entry +from pilgrim.models.photo import Photo + +from pilgrim.service.entry_service import EntryService + +@pytest.fixture(scope="function") +def db_session(): + engine = create_engine("sqlite:///:memory:") + + Base.metadata.create_all(engine) + Session = sessionmaker(bind=engine) + session = Session() + yield session + session.close() + Base.metadata.drop_all(engine) + +@pytest.fixture +def populated_db_session(db_session): + travel_diary = TravelDiary(name="My Travel Diary", directory_name="viagem-teste") + db_session.add(travel_diary) + db_session.commit() + return db_session + +def test_create_entry_successfully(populated_db_session): + session = populated_db_session + service = EntryService(session) + diary_id = 1 # Sabemos que o ID é 1 por causa da nossa fixture + title = "Primeiro Dia na Praia" + text = "O dia foi ensolarado e o mar estava ótimo." + date = datetime(2025, 7, 20) + photos = [Photo(filepath="/path/to/photo1.jpg",name="Photo 1",photo_hash="hash_12345678",fk_travel_diary_id=diary_id), Photo(filepath="/path/to/photo2.jpg",name="Photo 1",photo_hash="hash_87654321",fk_travel_diary_id=diary_id)] + created_entry = service.create( + travel_diary_id=diary_id, + title=title, + text=text, + date=date, + photos=photos + ) + assert created_entry is not None + assert created_entry.id is not None # Garante que foi salvo no BD e tem um ID + assert created_entry.title == title + assert created_entry.text == text + assert len(created_entry.photos) == 2 + assert created_entry.photos[0].filepath == "/path/to/photo1.jpg" + + entry_in_db = session.query(Entry).filter_by(id=created_entry.id).one() + assert entry_in_db.title == "Primeiro Dia na Praia" \ No newline at end of file From 3c7925cb1c5b4f05ee8a5107b5030c30fa38573b Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 15:21:49 -0300 Subject: [PATCH 2/7] test(entry_service): add a failure case test for create method This commit adds a unit test for an important "unhappy path" in the EntryService's `create` method. It specifically verifies that the method gracefully returns `None` when provided with a `travel_diary_id` that does not exist in the database, ensuring the initial guard clause works as expected. --- tests/service/test_entry_service.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index b2f1a6a..71cb97a 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -52,4 +52,19 @@ def test_create_entry_successfully(populated_db_session): assert created_entry.photos[0].filepath == "/path/to/photo1.jpg" entry_in_db = session.query(Entry).filter_by(id=created_entry.id).one() - assert entry_in_db.title == "Primeiro Dia na Praia" \ No newline at end of file + assert entry_in_db.title == "Primeiro Dia na Praia" + +def test_create_entry_fails_when_diary_id_is_invalid(db_session): + session = db_session + service = EntryService(session) + invalid_id = 666 + + result = service.create( + travel_diary_id=invalid_id, + title="Título de Teste", + text="Texto de Teste", + date=datetime(2025, 7, 20), + photos=[] + ) + + assert result is None \ No newline at end of file From 77e191f4803e3659f0b2c4e15b7905c3d963c7b7 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 16:03:45 -0300 Subject: [PATCH 3/7] test(entry_service): add test for creating an entry without photos This commit adds a unit test to ensure that the EntryService's `create` method correctly handles cases where an empty list of photos is provided. It verifies that the entry is created successfully and that the `photos` relationship is an empty list, confirming the feature's flexibility. --- tests/service/test_entry_service.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index 71cb97a..4acf8e5 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -67,4 +67,27 @@ def test_create_entry_fails_when_diary_id_is_invalid(db_session): photos=[] ) - assert result is None \ No newline at end of file + assert result is None + +def test_create_entry_successfully_without_photo(populated_db_session): + session = populated_db_session + service = EntryService(session) + diary_id = 1 # Sabemos que o ID é 1 por causa da nossa fixture + title = "Primeiro Dia na Praia" + text = "O dia foi ensolarado e o mar estava ótimo." + date = datetime(2025, 7, 20) + photos = [] + created_entry = service.create( + travel_diary_id=diary_id, + title=title, + text=text, + date=date, + photos=photos + ) + assert created_entry is not None + assert created_entry.id is not None # Garante que foi salvo no BD e tem um ID + assert created_entry.title == title + assert created_entry.text == text + assert len(created_entry.photos) == 0 + entry_in_db = session.query(Entry).filter_by(id=created_entry.id).one() + assert entry_in_db.title == "Primeiro Dia na Praia" \ No newline at end of file From 1c8026620cb7eb0e9a0b6628aeb807c22fd326fb Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 20:47:12 -0300 Subject: [PATCH 4/7] Add a test to test the creation of entries with null on nullable fields --- tests/service/test_entry_service.py | 42 ++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index 4acf8e5..b55999f 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -2,6 +2,7 @@ import pytest from datetime import datetime from unittest.mock import Mock from sqlalchemy import create_engine +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import sessionmaker from pilgrim.database import Base @@ -90,4 +91,43 @@ def test_create_entry_successfully_without_photo(populated_db_session): assert created_entry.text == text assert len(created_entry.photos) == 0 entry_in_db = session.query(Entry).filter_by(id=created_entry.id).one() - assert entry_in_db.title == "Primeiro Dia na Praia" \ No newline at end of file + assert entry_in_db.title == "Primeiro Dia na Praia" + +def test_create_entry_fails_with_null_title(populated_db_session): + session = populated_db_session + service = EntryService(session) + diary_id = 1 + with pytest.raises(IntegrityError): + service.create( + travel_diary_id=diary_id, + title=None, + text="Um texto qualquer.", + date=datetime.now(), + photos=[] + ) + +def test_create_entry_fails_with_null_date(populated_db_session): + session = populated_db_session + service = EntryService(session) + diary_id = 1 + with pytest.raises(IntegrityError): + service.create( + travel_diary_id=diary_id, + title="Sabado de sol", + text="Um texto qualquer.", + date=None, + photos=[] + ) + +def test_create_entry_fails_with_null_diary_id(populated_db_session): + session = populated_db_session + service = EntryService(session) + diary_id = 1 + result = service.create( + travel_diary_id=None, + title="Sabado de sol", + text="Um texto qualquer.", + date=datetime.now(), + photos=[] + ) + assert result is None \ No newline at end of file From cec1827635cc51da5df426cdcbe36f6f97b7649a Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 22:12:09 -0300 Subject: [PATCH 5/7] Add all tests to test the update of entries --- tests/service/test_entry_service.py | 89 ++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index b55999f..a9207ee 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -30,6 +30,19 @@ def populated_db_session(db_session): db_session.commit() return db_session +@pytest.fixture +def session_with_an_entry(populated_db_session): + session = populated_db_session + initial_entry = Entry( + title="Título Original", + text="Texto original.", + date=datetime(2025, 1, 1), + travel_diary_id=1 + ) + session.add(initial_entry) + session.commit() + return session, initial_entry.id + def test_create_entry_successfully(populated_db_session): session = populated_db_session service = EntryService(session) @@ -130,4 +143,78 @@ def test_create_entry_fails_with_null_diary_id(populated_db_session): date=datetime.now(), photos=[] ) - assert result is None \ No newline at end of file + assert result is None + +def test_update_entry_successfully(session_with_an_entry): + session, entry_id = session_with_an_entry + service = EntryService(session) + entry_src = session.query(Entry).filter_by(id=entry_id).one() + new_date = datetime(2025, 1, 2) + entry_dst = Entry( + title="Título Atualizado", + text="Texto atualizado.", + date=new_date, + travel_diary_id=1, # Mantemos o mesmo travel_diary_id + photos=[] + ) + updated_entry = service.update(entry_src, entry_dst) + assert updated_entry is not None + assert updated_entry.id == entry_id + assert updated_entry.title == "Título Atualizado" + assert updated_entry.text == "Texto atualizado." + entry_in_db = session.query(Entry).filter_by(id=entry_id).one() + assert entry_in_db.title == "Título Atualizado" + +def test_update_entry_fails_if_entry_does_not_exist(db_session): + service = EntryService(db_session) + non_existent_entry = Entry( + title="dummy", + text="dummy", + date=datetime.now(), + travel_diary_id=1) + non_existent_entry.id = 999 + entry_with_new_data = Entry(title="Novo Título", text="Novo Texto", date=datetime.now(), travel_diary_id=1) + result = service.update(non_existent_entry, entry_with_new_data) + assert result is None + +def test_update_fails_with_null_title(session_with_an_entry): + session, entry_id = session_with_an_entry + service = EntryService(session) + entry_src = session.query(Entry).filter_by(id=entry_id).one() + entry_dst = Entry( + title=None, + text="Texto atualizado.", + date=datetime.now(), + travel_diary_id=1, + photos=[] + ) + with pytest.raises(IntegrityError): + service.update(entry_src, entry_dst) + +def test_update_fails_with_null_date(session_with_an_entry): + session, entry_id = session_with_an_entry + service = EntryService(session) + entry_src = session.query(Entry).filter_by(id=entry_id).one() + entry_dst = Entry( + title=entry_src.title, + text="Texto atualizado.", + date=None, + travel_diary_id=1, + photos=[] + ) + with pytest.raises(IntegrityError): + service.update(entry_src, entry_dst) + +def test_update_fails_with_null_diary_id(session_with_an_entry): + session, entry_id = session_with_an_entry + service = EntryService(session) + entry_src = session.query(Entry).filter_by(id=entry_id).one() + entry_dst = Entry( + title=entry_src.title, + text="Texto atualizado.", + date=datetime.now(), + travel_diary_id=None, + photos=[] + ) + with pytest.raises(IntegrityError): + service.update(entry_src, entry_dst) \ No newline at end of file From 790a9ea3f0491ebbf4d903f7f165d30a012ab0cc Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 22:26:40 -0300 Subject: [PATCH 6/7] Add all tests to test the read of entries --- tests/service/test_entry_service.py | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index a9207ee..1877530 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -1,3 +1,5 @@ +from re import search + import pytest from datetime import datetime from unittest.mock import Mock @@ -43,6 +45,19 @@ def session_with_an_entry(populated_db_session): session.commit() return session, initial_entry.id +@pytest.fixture +def session_with_multiple_entries(populated_db_session): + """Fixture que cria um diário e duas entradas para ele.""" + session = populated_db_session + + entry1 = Entry(title="Entrada 1", text="Texto 1", date=datetime(2025, 1, 1), travel_diary_id=1) + entry2 = Entry(title="Entrada 2", text="Texto 2", date=datetime(2025, 1, 2), travel_diary_id=1) + + session.add_all([entry1, entry2]) + session.commit() + + return session + def test_create_entry_successfully(populated_db_session): session = populated_db_session service = EntryService(session) @@ -144,6 +159,34 @@ def test_create_entry_fails_with_null_diary_id(populated_db_session): photos=[] ) assert result is None +def test_ready_by_id_successfully(session_with_an_entry): + session,_ = session_with_an_entry + service = EntryService(session) + search_id = 1 + result = service.read_by_id(search_id) + assert result is not None +def test_ready_by_id_fails_when_id_is_invalid(db_session): + session = db_session + service = EntryService(session) + invalid_id = 666 + result = service.read_by_id(invalid_id) + assert result is None + +def test_read_all_returns_all_entries(session_with_multiple_entries): + session = session_with_multiple_entries + service = EntryService(session) + all_entries = service.read_all() + assert isinstance(all_entries, list) + assert len(all_entries) == 2 + assert all_entries[0].title == "Entrada 1" + assert all_entries[1].title == "Entrada 2" + +def test_read_all_returns_empty_list_on_empty_db(db_session): + session = db_session + service = EntryService(session) + all_entries = service.read_all() + assert isinstance(all_entries, list) + assert len(all_entries) == 0 def test_update_entry_successfully(session_with_an_entry): session, entry_id = session_with_an_entry From 1629b9d52c836dc4b75715281dea2003df250fb9 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sun, 20 Jul 2025 22:38:55 -0300 Subject: [PATCH 7/7] Add all tests to test the delete of entries --- tests/service/test_entry_service.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/service/test_entry_service.py b/tests/service/test_entry_service.py index 1877530..b28e3c1 100644 --- a/tests/service/test_entry_service.py +++ b/tests/service/test_entry_service.py @@ -260,4 +260,26 @@ def test_update_fails_with_null_diary_id(session_with_an_entry): photos=[] ) with pytest.raises(IntegrityError): - service.update(entry_src, entry_dst) \ No newline at end of file + service.update(entry_src, entry_dst) + +def test_delete_successfully_removes_entry(session_with_an_entry): + session, entry_id = session_with_an_entry + service = EntryService(session) + entry_to_delete = service.read_by_id(entry_id) + assert entry_to_delete is not None + deleted_entry = service.delete(entry_to_delete) + assert deleted_entry is not None + assert deleted_entry.id == entry_id + entry_in_db = service.read_by_id(entry_id) + assert entry_in_db is None + +def test_delete_returns_none_if_entry_does_not_exist(db_session): + service = EntryService(db_session) + non_existent_entry = Entry( + title="dummy", + text="dummy", + date=datetime.now(), + travel_diary_id=1) + non_existent_entry.id = 999 + result = service.delete(non_existent_entry) + assert result is None