diff --git a/test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000..31a9a72 Binary files /dev/null and b/test/repository/__pycache__/test_answer_repository.cpython-310-pytest-8.3.4.pyc differ diff --git a/test/repository/__pycache__/test_quiz_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_quiz_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000..00fcf71 Binary files /dev/null and b/test/repository/__pycache__/test_quiz_repository.cpython-310-pytest-8.3.4.pyc differ diff --git a/test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000..18afc94 Binary files /dev/null and b/test/repository/__pycache__/test_session_repository.cpython-310-pytest-8.3.4.pyc differ diff --git a/test/repository/__pycache__/test_subject_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_subject_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000..431796a Binary files /dev/null and b/test/repository/__pycache__/test_subject_repository.cpython-310-pytest-8.3.4.pyc differ diff --git a/test/repository/__pycache__/test_user_repository.cpython-310-pytest-8.3.4.pyc b/test/repository/__pycache__/test_user_repository.cpython-310-pytest-8.3.4.pyc new file mode 100644 index 0000000..89f8474 Binary files /dev/null and b/test/repository/__pycache__/test_user_repository.cpython-310-pytest-8.3.4.pyc differ diff --git a/test/repository/test_answer_repository.py b/test/repository/test_answer_repository.py new file mode 100644 index 0000000..431ba45 --- /dev/null +++ b/test/repository/test_answer_repository.py @@ -0,0 +1,109 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories import UserAnswerRepository +from app.models import UserAnswerEntity +from app.models.entities import AnswerItemEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return UserAnswerRepository(db=mock_db) + + +def generate_dummy_answer_entity() -> UserAnswerEntity: + return UserAnswerEntity( + session_id="session123", + quiz_id=str(ObjectId()), + user_id="user123", + answered_at=datetime.utcnow(), + answers=[ + AnswerItemEntity( + question_index=0, answer="B", is_correct=True, time_spent=10 + ) + ], + total_score=80, + total_correct=4, + ) + + +def test_create(repository): + dummy_entity = generate_dummy_answer_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(dummy_entity) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_by_id_found(repository): + dummy_entity = generate_dummy_answer_entity() + data = dummy_entity.model_dump(by_alias=True) + data["_id"] = ObjectId() + + repository.collection.find_one.return_value = data + + result = repository.get_by_id(str(data["_id"])) + + assert isinstance(result, UserAnswerEntity) + assert result.user_id == dummy_entity.user_id + assert result.quiz_id == dummy_entity.quiz_id + + +def test_get_by_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.get_by_id(str(ObjectId())) + + assert result is None + + +def test_get_by_user_and_quiz(repository): + quiz_id = ObjectId() + repository.collection.find.return_value = [ + {"_id": ObjectId(), "user_id": "u1", "quiz_id": quiz_id} + ] + + result = repository.get_by_user_and_quiz("u1", str(quiz_id)) + + repository.collection.find.assert_called_once_with( + {"user_id": "u1", "quiz_id": quiz_id} + ) + assert isinstance(result, list) + + +def test_get_by_user(repository): + dummy_data = [generate_dummy_answer_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = dummy_data + + result = repository.get_by_user("user123") + + assert isinstance(result, list) + assert all(isinstance(item, UserAnswerEntity) for item in result) + + +def test_get_by_session(repository): + session_id = ObjectId() + repository.collection.find.return_value = [{"session_id": str(session_id)}] + + result = repository.get_by_session(str(session_id)) + + repository.collection.find.assert_called_once_with({"session_id": session_id}) + assert isinstance(result, list) + assert result[0]["session_id"] == str(session_id) + + +def test_delete_by_id(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete_by_id(str(ObjectId())) + + assert result is True diff --git a/test/repository/test_quiz_repository.py b/test/repository/test_quiz_repository.py new file mode 100644 index 0000000..8bbdefa --- /dev/null +++ b/test/repository/test_quiz_repository.py @@ -0,0 +1,171 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories import QuizRepository +from app.models.entities import QuizEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return QuizRepository(db=mock_db) + + +def generate_quiz_entity(**kwargs) -> QuizEntity: + return QuizEntity( + subject_id=kwargs.get("subject_id", "subject1"), + title=kwargs.get("title", "Kuis Sejarah Indonesia"), + description=kwargs.get( + "description", "Soal mengenai peristiwa penting Indonesia" + ), + is_public=kwargs.get("is_public", True), + date=kwargs.get("date", datetime.now()), + total_quiz=kwargs.get("total_quiz", 10), + limit_duration=kwargs.get("limit_duration", 30), + total_user_playing=kwargs.get("total_user_playing", 100), + question_listings=[], + author_id=kwargs.get("author_id", "guru123"), + ) + + +def test_create_quiz(repository): + quiz = generate_quiz_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(quiz) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_by_id_found(repository): + quiz_id = ObjectId() + quiz_data = generate_quiz_entity().model_dump(by_alias=True) + quiz_data["_id"] = quiz_id + repository.collection.find_one.return_value = quiz_data + + result = repository.get_by_id(str(quiz_id)) + + assert isinstance(result, QuizEntity) + assert result.id == quiz_id + + +def test_get_by_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.get_by_id(str(ObjectId())) + + assert result is None + + +def test_search_by_title_or_category(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.search_by_title_or_category( + keyword="Indonesia", + subject_id=None, + page=1, + page_size=10, + ) + + assert len(result) == 1 + assert isinstance(result[0], QuizEntity) + + +def test_count_by_search(repository): + repository.collection.count_documents.return_value = 3 + + result = repository.count_by_search("sejarah") + + assert result == 3 + + +def test_get_by_ids(repository): + qid1, qid2 = ObjectId(), ObjectId() + data = [generate_quiz_entity().model_dump(by_alias=True) for _ in range(2)] + data[0]["_id"] = qid1 + data[1]["_id"] = qid2 + repository.collection.find.return_value = data + + result = repository.get_by_ids([str(qid1), str(qid2)]) + + assert result is not None + assert all(isinstance(q, QuizEntity) for q in result) + + +def test_get_by_user_id(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_by_user_id("guru123") + + assert isinstance(result, list) + assert isinstance(result[0], QuizEntity) + + +def test_get_all(repository): + mock_cursor = MagicMock() + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_all() + + assert len(result) == 1 + assert isinstance(result[0], QuizEntity) + + +def test_update(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update(str(ObjectId()), {"title": "Update Title"}) + + assert result is True + + +def test_update_user_playing(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update_user_playing(str(ObjectId()), 123) + + assert result is True + + +def test_delete(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete(str(ObjectId())) + + assert result is True + + +def test_count_by_user_id(repository): + repository.collection.count_documents.return_value = 7 + + result = repository.count_by_user_id("guru123") + + assert result == 7 + + +def test_get_top_played_quizzes(repository): + mock_cursor = MagicMock() + mock_cursor.sort.return_value = mock_cursor + mock_cursor.skip.return_value = mock_cursor + mock_cursor.limit.return_value = [generate_quiz_entity().model_dump(by_alias=True)] + repository.collection.find.return_value = mock_cursor + + result = repository.get_top_played_quizzes() + + assert isinstance(result, list) + assert isinstance(result[0], QuizEntity) diff --git a/test/repository/test_session_repository.py b/test/repository/test_session_repository.py new file mode 100644 index 0000000..590f411 --- /dev/null +++ b/test/repository/test_session_repository.py @@ -0,0 +1,116 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories import SessionRepository +from app.models.entities import SessionEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return SessionRepository(db=mock_db) + + +def generate_session_entity() -> SessionEntity: + return SessionEntity( + session_code="ABC123", + quiz_id="quiz1", + host_id="user1", + created_at=datetime.now(), + started_at=None, + ended_at=None, + is_active=True, + participan_limit=5, + participants=["user1"], + current_question_index=0, + ) + + +def test_insert_session(repository): + session = generate_session_entity() + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.insert(session) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_find_by_session_id_found(repository): + session = generate_session_entity() + doc = session.model_dump(by_alias=True) + repository.collection.find_one.return_value = doc + + result = repository.find_by_session_id(session_id=doc["_id"]) + + assert isinstance(result, SessionEntity) + assert result.session_code == "ABC123" + + +def test_find_by_session_id_not_found(repository): + repository.collection.find_one.return_value = None + + result = repository.find_by_session_id("nonexistent_id") + + assert result is None + + +def test_find_by_session_code_found(repository): + session = generate_session_entity() + doc = session.model_dump(by_alias=True) + repository.collection.find_one.return_value = doc + + result = repository.find_by_session_code("ABC123") + + assert isinstance(result, SessionEntity) + assert result.quiz_id == "quiz1" + + +def test_update_session(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + update_data = {"is_active": False} + result = repository.update("session123", update_data) + + repository.collection.update_one.assert_called_once_with( + {"_id": "session123"}, {"$set": update_data} + ) + assert result is True + + +def test_add_participant(repository): + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.add_participant("session123", "user999") + + repository.collection.update_one.assert_called_once_with( + {"_id": "session123"}, {"$addToSet": {"participants": "user999"}} + ) + assert result is True + + +def test_delete_session(repository): + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete("session123") + + repository.collection.delete_one.assert_called_once_with({"_id": "session123"}) + assert result is True + + +def test_list_active_sessions(repository): + doc = generate_session_entity().model_dump(by_alias=True) + repository.collection.find.return_value = [doc] + + result = repository.list_active_sessions() + + repository.collection.find.assert_called_once_with({"is_active": True}) + assert len(result) == 1 + assert isinstance(result[0], SessionEntity) + assert result[0].is_active is True diff --git a/test/repository/test_subject_repository.py b/test/repository/test_subject_repository.py new file mode 100644 index 0000000..16e5541 --- /dev/null +++ b/test/repository/test_subject_repository.py @@ -0,0 +1,139 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from app.repositories.subject_repository import SubjectRepository +from app.models.entities import SubjectEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def repository(mock_db): + return SubjectRepository(db=mock_db) + + +def generate_subject(name, short_name, desc, icon="") -> SubjectEntity: + return SubjectEntity(name=name, short_name=short_name, description=desc, icon=icon) + + +def test_create_subject(repository): + subject = generate_subject( + name="Sejarah Indonesia", + short_name="SEJARAH", + desc="Mempelajari peristiwa dan tokoh penting dalam sejarah nasional.", + ) + insert_result = MagicMock(inserted_id=ObjectId()) + repository.collection.insert_one.return_value = insert_result + + result = repository.create(subject) + + repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_get_all_subjects(repository): + mock_data = [ + generate_subject( + "Biologi", + "BIO", + "Ilmu yang mempelajari makhluk hidup dan lingkungannya.", + ).model_dump(by_alias=True), + generate_subject( + "Fisika", + "FIS", + "Mempelajari fenomena alam seperti gaya, energi, dan gerak.", + ).model_dump(by_alias=True), + ] + repository.collection.find.return_value = mock_data + + result = repository.get_all() + + assert len(result) == 2 + assert result[0].name == "Biologi" + assert result[1].short_name == "FIS" + + +def test_get_by_id_valid(repository): + oid = ObjectId() + doc = generate_subject( + "Geografi", + "GEO", + "Studi tentang lokasi, wilayah, dan interaksi manusia-lingkungan.", + ).model_dump(by_alias=True) + doc["_id"] = oid + repository.collection.find_one.return_value = doc + + result = repository.get_by_id(str(oid)) + + assert isinstance(result, SubjectEntity) + assert result.name == "Geografi" + assert result.id == oid + + +def test_get_by_id_invalid(repository): + result = repository.get_by_id("invalid_id") + assert result is None + + +def test_get_by_ids_mixed(repository): + oid1 = ObjectId() + oid2 = ObjectId() + ids = [str(oid1), "invalid_id", str(oid2)] + + mock_docs = [ + { + **generate_subject( + "Kimia", + "KIM", + "Ilmu tentang zat dan reaksinya", + ).model_dump(by_alias=True), + "_id": oid1, + }, + { + **generate_subject( + "Ekonomi", + "EKO", + "Analisis produksi, distribusi, dan konsumsi", + ).model_dump(by_alias=True), + "_id": oid2, + }, + ] + repository.collection.find.return_value = mock_docs + + result = repository.get_by_ids(ids) + + assert len(result) == 2 + assert result[0].short_name == "KIM" + assert result[1].name == "Ekonomi" + + +def test_update_valid(repository): + oid = ObjectId() + repository.collection.update_one.return_value = MagicMock(modified_count=1) + + result = repository.update(str(oid), {"description": "Updated Description"}) + + assert result is True + + +def test_update_invalid(repository): + result = repository.update("invalid_object_id", {"name": "Something"}) + + assert result is False + + +def test_delete_valid(repository): + oid = ObjectId() + repository.collection.delete_one.return_value = MagicMock(deleted_count=1) + + result = repository.delete(str(oid)) + + assert result is True + + +def test_delete_invalid(repository): + result = repository.delete("invalid_object_id") + assert result is False diff --git a/test/repository/test_user_repository.py b/test/repository/test_user_repository.py new file mode 100644 index 0000000..82f8414 --- /dev/null +++ b/test/repository/test_user_repository.py @@ -0,0 +1,155 @@ +import pytest +from unittest.mock import MagicMock +from bson import ObjectId +from datetime import datetime +from app.repositories.user_repository import UserRepository +from app.models.entities import UserEntity + + +@pytest.fixture +def mock_db(): + return MagicMock() + + +@pytest.fixture +def user_repository(mock_db): + return UserRepository(db=mock_db) + + +def test_get_all_users(user_repository): + mock_users = [ + { + "_id": ObjectId(), + "email": "a@example.com", + "name": "A", + "password": "pass1", + "locale": "id-ID", + }, + { + "_id": ObjectId(), + "email": "b@example.com", + "name": "B", + "password": "pass2", + "locale": "id-ID", + }, + ] + user_repository.collection.find.return_value = mock_users + + result = user_repository.get_all_users() + + assert len(result) == 2 + assert all(isinstance(user, UserEntity) for user in result) + assert result[0].email == "a@example.com" + assert result[1].name == "B" + + +def test_get_user_by_email_found(user_repository): + mock_user = { + "_id": ObjectId(), + "email": "john@example.com", + "name": "John Doe", + "password": "hashed", + "birth_date": datetime(2000, 1, 1), + "locale": "en-US", + "phone": "08123456789", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_user_by_email("john@example.com") + + assert isinstance(result, UserEntity) + assert result.email == "john@example.com" + assert result.name == "John Doe" + + +def test_get_user_by_email_not_found(user_repository): + user_repository.collection.find_one.return_value = None + + result = user_repository.get_user_by_email("notfound@example.com") + + assert result is None + + +def test_get_user_by_id_found(user_repository): + user_id = ObjectId() + mock_user = { + "_id": user_id, + "email": "jane@example.com", + "name": "Jane", + "password": "hashed", + "birth_date": datetime(1990, 1, 1), + "locale": "en-US", + "phone": "089999999", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_user_by_id(str(user_id)) + + assert isinstance(result, UserEntity) + assert str(result.id) == str(user_id) + assert result.name == "Jane" + + +def test_get_by_google_id_found(user_repository): + mock_user = { + "_id": ObjectId(), + "google_id": "google-123", + "email": "google@example.com", + "name": "Google User", + "locale": "en-US", + } + user_repository.collection.find_one.return_value = mock_user + + result = user_repository.get_by_google_id("google-123") + + assert isinstance(result, UserEntity) + assert result.google_id == "google-123" + assert result.email == "google@example.com" + + +def test_insert_user(user_repository): + user_entity = UserEntity( + name="Test", + email="test@example.com", + password="123", + birth_date=datetime(2000, 1, 1), + phone="081111111", + locale="id-ID", + ) + mock_insert_result = MagicMock(inserted_id=ObjectId()) + user_repository.collection.insert_one.return_value = mock_insert_result + + result = user_repository.insert_user(user_entity) + + user_repository.collection.insert_one.assert_called_once() + assert isinstance(result, str) + + +def test_update_user(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(modified_count=1) + user_repository.collection.update_one.return_value = mock_result + + result = user_repository.update_user(user_id, {"name": "Updated Name"}) + + assert result is True + + +def test_update_user_field(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(modified_count=1) + user_repository.collection.update_one.return_value = mock_result + + result = user_repository.update_user_field(user_id, "phone", "0822334455") + + assert result is True + + +def test_delete_user(user_repository): + user_id = str(ObjectId()) + mock_result = MagicMock(deleted_count=1) + user_repository.collection.delete_one.return_value = mock_result + + result = user_repository.delete_user(user_id) + + assert result is True