Spiritual_Health_Project / tests /chaplain_feedback /test_properties_data_models.py
DocUA's picture
Fix CSV download button for Hugging Face Spaces - use DownloadButton for direct file download
ab93d81
# 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