# test_properties_data_models.py """ Property-based tests for Chaplain Feedback data model serialization. Tests that all data models serialize and deserialize correctly (round-trip). """ import pytest from hypothesis import given, settings from datetime import datetime from src.core.chaplain_models import ( DistressIndicator, FollowUpQuestion, ClassificationFlowResult, TaggingRecord, InteractionStepLog, INDICATOR_DEFINITIONS, ) from tests.chaplain_feedback.conftest import ( distress_indicator_strategy, follow_up_question_strategy, classification_flow_result_strategy, tagging_record_strategy, interaction_step_log_strategy, interaction_step_log_with_tagging_strategy, ) class TestDistressIndicatorRoundTrip: """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** Tests that DistressIndicator serializes and deserializes correctly. """ @given(distress_indicator_strategy()) @settings(max_examples=100) def test_distress_indicator_round_trip(self, indicator): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any DistressIndicator, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back indicator_dict = indicator.to_dict() restored = DistressIndicator.from_dict(indicator_dict) # Verify all fields match assert restored.indicator_text == indicator.indicator_text assert restored.category == indicator.category assert restored.subcategory == indicator.subcategory assert restored.severity == indicator.severity assert restored.confidence == indicator.confidence assert restored.definition_reference == indicator.definition_reference def test_distress_indicator_from_definition(self): """ Test creating DistressIndicator from INDICATOR_DEFINITIONS. """ # Test with a known indicator indicator = DistressIndicator.from_definition( indicator_key="excessive_guilt", indicator_text="I feel so guilty about everything", confidence=0.85 ) assert indicator.category == "Guilt" assert indicator.subcategory == "Excessive guilt" assert indicator.severity == "red" assert indicator.definition_reference == "II.D" assert indicator.confidence == 0.85 class TestFollowUpQuestionRoundTrip: """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** Tests that FollowUpQuestion serializes and deserializes correctly. """ @given(follow_up_question_strategy()) @settings(max_examples=100) def test_follow_up_question_round_trip(self, question): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any FollowUpQuestion, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back question_dict = question.to_dict() restored = FollowUpQuestion.from_dict(question_dict) # Verify all fields match assert restored.question_id == question.question_id assert restored.question_text == question.question_text assert restored.purpose == question.purpose class TestClassificationFlowResultRoundTrip: """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** Tests that ClassificationFlowResult serializes and deserializes correctly. """ @given(classification_flow_result_strategy()) @settings(max_examples=100) def test_classification_flow_result_round_trip(self, result): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any ClassificationFlowResult, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back result_dict = result.to_dict() restored = ClassificationFlowResult.from_dict(result_dict) # Verify basic fields match assert restored.classification == result.classification assert restored.confidence == result.confidence assert restored.explanation == result.explanation assert restored.permission_check_message == result.permission_check_message assert restored.referral_message == result.referral_message assert restored.consent_status == result.consent_status assert restored.patient_responses == result.patient_responses assert restored.re_evaluation_result == result.re_evaluation_result # Verify nested indicators assert len(restored.indicators) == len(result.indicators) for orig, rest in zip(result.indicators, restored.indicators): assert rest.indicator_text == orig.indicator_text assert rest.category == orig.category assert rest.severity == orig.severity # Verify nested follow-up questions assert len(restored.follow_up_questions) == len(result.follow_up_questions) for orig, rest in zip(result.follow_up_questions, restored.follow_up_questions): assert rest.question_id == orig.question_id assert rest.question_text == orig.question_text assert rest.purpose == orig.purpose class TestTaggingRecordRoundTrip: """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** Tests that TaggingRecord serializes and deserializes correctly. """ @given(tagging_record_strategy()) @settings(max_examples=100) def test_tagging_record_round_trip(self, record): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any TaggingRecord, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back record_dict = record.to_dict() restored = TaggingRecord.from_dict(record_dict) # Verify all fields match assert restored.record_id == record.record_id assert restored.message_id == record.message_id assert restored.is_classification_correct == record.is_classification_correct assert restored.classification_subcategory == record.classification_subcategory assert restored.correct_classification == record.correct_classification assert restored.question_issues == record.question_issues assert restored.question_comments == record.question_comments assert restored.referral_issues == record.referral_issues assert restored.referral_comments == record.referral_comments assert restored.indicator_issues == record.indicator_issues assert restored.indicator_comments == record.indicator_comments assert restored.general_notes == record.general_notes class TestInteractionStepLogRoundTrip: """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** Tests that InteractionStepLog serializes and deserializes correctly. """ @given(interaction_step_log_strategy()) @settings(max_examples=100) def test_interaction_step_log_round_trip(self, log): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any InteractionStepLog, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back log_dict = log.to_dict() restored = InteractionStepLog.from_dict(log_dict) # Verify all fields match assert restored.step_id == log.step_id assert restored.session_id == log.session_id assert restored.message_id == log.message_id assert restored.step_type == log.step_type assert restored.input_text == log.input_text assert restored.model_output == log.model_output assert restored.approval_status == log.approval_status assert restored.tagging_data == log.tagging_data @given(interaction_step_log_with_tagging_strategy()) @settings(max_examples=100) def test_interaction_step_log_with_tagging_round_trip(self, log): """ **Feature: chaplain-feedback-system, Property: Data Model Round Trip** **Validates: Requirements 8.5** For any InteractionStepLog with nested TaggingRecord, converting to dict and back should preserve all fields exactly. """ # Convert to dict and back log_dict = log.to_dict() restored = InteractionStepLog.from_dict(log_dict) # Verify basic fields match assert restored.step_id == log.step_id assert restored.session_id == log.session_id assert restored.message_id == log.message_id assert restored.step_type == log.step_type assert restored.input_text == log.input_text assert restored.model_output == log.model_output assert restored.approval_status == log.approval_status # Verify nested tagging data if log.tagging_data is None: assert restored.tagging_data is None else: assert restored.tagging_data is not None assert restored.tagging_data.record_id == log.tagging_data.record_id assert restored.tagging_data.message_id == log.tagging_data.message_id assert restored.tagging_data.is_classification_correct == log.tagging_data.is_classification_correct assert restored.tagging_data.question_issues == log.tagging_data.question_issues assert restored.tagging_data.referral_issues == log.tagging_data.referral_issues