File size: 10,043 Bytes
ab93d81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# 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