"""Tests for score_history model.""" import json from contextlib import nullcontext as does_not_raise from datetime import datetime import pytest from freezegun import freeze_time from product_review.api import db from product_review.models import score_history as score_history_model from tests.utils.db_utils import create_test_review_queue_item def create_test_score_history( review_queue_id, validation_result="PASS", confidence_score=95, score_version=1.0 ): """Create a test score history record.""" score = score_history_model.ScoreHistory( review_queue_id=review_queue_id, validation_result=validation_result, failed_validations=None, confidence_score=confidence_score, score_reasoning={"reason": "test"}, score_version=score_version, auto_approved=False, ) db.session.add(score) db.session.commit() return score @pytest.mark.parametrize( ( "test_description", "review_queue_id", "validation_result", "failed_validations", "confidence_score", "score_reasoning", "auto_approved", "score_version", "existing_scores", "expected_raise", "expected_raise_message", ), [ ( "success with PASS validation", 1, "PASS", None, 95, {"reason": "High quality"}, True, 1.0, [], does_not_raise(), "None", ), ( "success with FAIL validation and failed_validations", 1, "FAIL", ["validation_1", "validation_2"], 30, {"details": "Failed validations"}, False, 1.0, [], does_not_raise(), "None", ), ( "success with auto_approved", 1, "PASS", None, 100, {"reason": "Auto approved"}, True, 1.5, [], does_not_raise(), "None", ), ( "review queue item not found", 999, "PASS", None, 95, {"reason": "Test"}, False, 1.0, [], pytest.raises(Exception), json.dumps( { "status": 404, "code": "not_found", "message": 'Review queue item with id "999" not found.', } ), ), ( "duplicate score for same review_queue_id and score_version", 1, "PASS", None, 95, {"reason": "Duplicate"}, False, 1.0, [{"review_queue_id": 1, "score_version": 1.0}], pytest.raises(Exception), json.dumps( { "status": 409, "code": "exists", "message": 'There is already a score record for "review_queue_id: 1" and "score_version: 1.0".', # noqa } ), ), ], ) @freeze_time("2025-11-11 10:00:00") def test_add_score( app_context, test_description, review_queue_id, validation_result, failed_validations, confidence_score, score_reasoning, auto_approved, score_version, existing_scores, expected_raise, expected_raise_message, ): """Test add_score.""" # Create review queue item for valid cases if review_queue_id != 999: create_test_review_queue_item( review_queue_id=review_queue_id, product_id=100, status="new" ) # Create existing scores if specified for existing in existing_scores: create_test_score_history( review_queue_id=existing["review_queue_id"], score_version=existing["score_version"], ) with expected_raise as er: score_history_model.add_score( review_queue_id=review_queue_id, validation_result=validation_result, failed_validations=failed_validations, confidence_score=confidence_score, score_reasoning=score_reasoning, auto_approved=auto_approved, score_version=score_version, ) db.session.commit() assert str(getattr(er, "value", None)) == expected_raise_message # Verify the score was added for success cases if expected_raise_message == "None": scores = score_history_model.ScoreHistory.query.filter_by( review_queue_id=review_queue_id, score_version=score_version ).all() assert len(scores) == 1 score = scores[0] assert score.validation_result == validation_result assert score.failed_validations == failed_validations assert score.confidence_score == confidence_score assert score.score_reasoning == score_reasoning assert score.auto_approved == auto_approved assert float(score.score_version) == float(score_version) def test_to_dict(app_context): """Test ScoreHistory.to_dict method.""" create_test_review_queue_item(review_queue_id=1, product_id=100, status="new") score = score_history_model.ScoreHistory( review_queue_id=1, validation_result="PASS", failed_validations=["validation_1"], confidence_score=85, score_reasoning={"reason": "Good quality"}, score_version=1.0, auto_approved=True, ) db.session.add(score) db.session.commit() score_dict = score.to_dict() assert "score_history_id" in score_dict assert score_dict["review_queue_id"] == 1 assert score_dict["validation_result"] == "PASS" assert score_dict["failed_validations"] == ["validation_1"] assert score_dict["confidence_score"] == 85 assert score_dict["score_reasoning"] == {"reason": "Good quality"} assert float(score_dict["score_version"]) == 1.0 assert score_dict["auto_approved"] is True assert "created_datetime" in score_dict assert isinstance(score_dict["score_version"], float) assert isinstance(score_dict['score_history_id'], int) assert isinstance(score_dict['confidence_score'], int) assert isinstance(score_dict['validation_result'], str) assert isinstance(score_dict['score_reasoning'], dict) assert isinstance(score_dict['created_datetime'], datetime) assert isinstance(score_dict['failed_validations'], list) @pytest.mark.parametrize("test_scores,expected_data", [ ( [ {"score_version": 1.5, "confidence_score": 75, "failed_validations": ["Y"]}, {"score_version": 1.7, "confidence_score": 80, "failed_validations": []}, {"score_version": 1.2, "confidence_score": 70, "failed_validations": ["Y"]} ], {"score_version": 1.7, "confidence_score": 80, "failed_validations": []} ), ( [ {"score_version": 1.0, "confidence_score": 95, "failed_validations": []}, {"score_version": 2.0, "confidence_score": 80, "failed_validations": ["Y"]}, ], {"score_version": 2.0, "confidence_score": 80, "failed_validations": ["Y"]} ) ]) def test_get_score_exists(test_scores, expected_data): """Test that get_score returns the entry with latest score_version.""" create_test_review_queue_item(review_queue_id=1, product_id=100, status="new") for score_data in test_scores: score = score_history_model.ScoreHistory( review_queue_id=1, validation_result="PASS", failed_validations=score_data["failed_validations"], confidence_score=score_data["confidence_score"], score_reasoning={"reason": "Test"}, score_version=score_data["score_version"], auto_approved=True, ) db.session.add(score) db.session.commit() result = score_history_model.get_score(1) for key, expected_value in expected_data.items(): assert result[key] == expected_value assert result["review_queue_id"] == 1 assert result["validation_result"] == "PASS"