File size: 18,073 Bytes
24214fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#!/usr/bin/env python3
"""
Test script for the consent response processor.
Tests Task 5.3 implementation.
"""

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'src'))

from config.prompt_management.consent_response_processor import (
    ConsentResponseProcessor, ProcessingAction, ReferralUrgency, ProcessingResult
)
from config.prompt_management.consent_manager import ConsentInteraction, ConsentMessageType, ConsentResponse
from datetime import datetime


def test_consent_response_processor_initialization():
    """Test that the consent response processor initializes correctly."""
    print("Testing consent response processor initialization...")
    
    processor = ConsentResponseProcessor()
    
    # Verify components are initialized
    assert hasattr(processor, 'consent_manager')
    assert hasattr(processor, 'message_generator')
    assert hasattr(processor, 'processing_rules')
    assert hasattr(processor, 'medical_transition_phrases')
    
    # Verify processing rules structure
    assert 'clarification_attempts_limit' in processor.processing_rules
    assert 'follow_up_delay_hours' in processor.processing_rules
    assert 'urgency_indicators' in processor.processing_rules
    
    # Verify urgency indicators
    urgency_indicators = processor.processing_rules['urgency_indicators']
    assert 'high' in urgency_indicators
    assert 'medium' in urgency_indicators
    assert 'low' in urgency_indicators
    
    # Verify medical transition phrases
    assert len(processor.medical_transition_phrases) > 0
    for phrase in processor.medical_transition_phrases:
        assert isinstance(phrase, str)
        assert len(phrase) > 0
    
    print("βœ“ Consent response processor initializes correctly")


def test_acceptance_processing():
    """Test processing of patient acceptance responses."""
    print("Testing acceptance processing...")
    
    processor = ConsentResponseProcessor()
    
    # Test basic acceptance
    accept_response = "Yes, I would like to speak with someone"
    context = {'distress_level': 'medium', 'message_content': 'I feel overwhelmed'}
    
    result = processor.process_patient_response(accept_response, "test_session_1", context)
    
    # Verify result structure
    assert isinstance(result, ProcessingResult)
    assert result.action == ProcessingAction.PROCEED_WITH_REFERRAL
    assert result.generate_provider_summary == True
    assert result.log_referral == True
    assert result.referral_urgency is not None
    assert result.requires_follow_up == False
    
    # Verify interaction record
    interaction = result.interaction_record
    assert interaction.patient_response == accept_response
    assert interaction.response_classification == ConsentResponse.ACCEPT
    assert interaction.message_type == ConsentMessageType.CONFIRMATION
    
    # Verify next steps
    assert len(result.next_steps) > 0
    assert any('provider summary' in step.lower() for step in result.next_steps)
    assert any('log referral' in step.lower() for step in result.next_steps)
    
    # Verify context updates
    assert result.context_updates['consent_status'] == 'accepted'
    assert result.context_updates['provider_contact_required'] == True
    
    print("βœ“ Acceptance processing works correctly")


def test_decline_processing():
    """Test processing of patient decline responses."""
    print("Testing decline processing...")
    
    processor = ConsentResponseProcessor()
    
    # Test decline response
    decline_response = "No, I'm fine"
    context = {'distress_level': 'low'}
    
    result = processor.process_patient_response(decline_response, "test_session_2", context)
    
    # Verify result structure
    assert result.action == ProcessingAction.RETURN_TO_MEDICAL_DIALOGUE
    assert result.generate_provider_summary == False
    assert result.log_referral == False
    assert result.referral_urgency is None
    assert result.requires_follow_up == False
    
    # Verify message contains both acknowledgment and medical transition
    message = result.message
    assert len(message) > 0
    # Should contain elements from both acknowledgment and transition
    assert any(word in message.lower() for word in ['understand', 'respect', 'decision'])
    assert any(word in message.lower() for word in ['medical', 'healthcare', 'continue'])
    
    # Verify interaction record
    interaction = result.interaction_record
    assert interaction.patient_response == decline_response
    assert interaction.response_classification == ConsentResponse.DECLINE
    assert interaction.message_type == ConsentMessageType.DECLINE_ACKNOWLEDGMENT
    
    # Verify next steps include medical dialogue return
    assert any('medical dialogue' in step.lower() for step in result.next_steps)
    assert any('healthcare' in step.lower() for step in result.next_steps)
    
    # Verify context updates
    assert result.context_updates['consent_status'] == 'declined'
    assert result.context_updates['spiritual_care_declined'] == True
    assert result.context_updates['return_to_medical_dialogue'] == True
    
    print("βœ“ Decline processing works correctly")


def test_ambiguous_response_processing():
    """Test processing of ambiguous patient responses."""
    print("Testing ambiguous response processing...")
    
    processor = ConsentResponseProcessor()
    
    # Test ambiguous response
    ambiguous_response = "I don't know, what would that involve?"
    context = {'distress_level': 'medium'}
    
    result = processor.process_patient_response(ambiguous_response, "test_session_3", context)
    
    # Verify result structure
    assert result.action == ProcessingAction.REQUEST_CLARIFICATION
    assert result.generate_provider_summary == False
    assert result.log_referral == False
    assert result.referral_urgency is None
    assert result.requires_follow_up == True
    assert result.follow_up_delay_hours is not None
    
    # Verify interaction record
    interaction = result.interaction_record
    assert interaction.patient_response == ambiguous_response
    assert interaction.response_classification == ConsentResponse.AMBIGUOUS
    assert interaction.message_type == ConsentMessageType.CLARIFICATION
    assert interaction.requires_clarification == True
    assert interaction.clarification_attempts == 1
    
    # Verify clarification message
    assert len(result.message) > 0
    # Should be informative for information-seeking ambiguity
    assert any(word in result.message.lower() for word in ['chaplain', 'counselor', 'support', 'team'])
    
    # Verify context updates
    assert result.context_updates['consent_status'] == 'clarification_needed'
    assert result.context_updates['clarification_attempts'] == 1
    assert result.context_updates['awaiting_clarification'] == True
    
    print("βœ“ Ambiguous response processing works correctly")


def test_clarification_attempt_limits():
    """Test clarification attempt limits and escalation."""
    print("Testing clarification attempt limits...")
    
    processor = ConsentResponseProcessor()
    
    # Create interaction history with multiple clarification attempts
    interaction_history = []
    for i in range(3):  # 3 previous clarification attempts
        interaction = ConsentInteraction(
            interaction_id=f"test_{i}",
            message_type=ConsentMessageType.CLARIFICATION,
            message_content=f"Clarification {i}",
            patient_response=f"Response {i}",
            response_classification=ConsentResponse.AMBIGUOUS,
            timestamp=datetime.now(),
            session_id="test_session_4",
            requires_clarification=True,
            clarification_attempts=i
        )
        interaction_history.append(interaction)
    
    # Test response that would exceed limit
    ambiguous_response = "I'm still not sure"
    result = processor.process_patient_response(
        ambiguous_response, "test_session_4", {}, interaction_history
    )
    
    # Should escalate to human
    assert result.action == ProcessingAction.ESCALATE_TO_HUMAN
    assert result.requires_follow_up == True
    assert result.follow_up_delay_hours == 4  # Human review within 4 hours
    
    # Verify context updates indicate escalation
    assert result.context_updates['consent_status'] == 'escalated_to_human'
    assert result.context_updates['human_review_required'] == True
    assert 'escalation_reason' in result.context_updates
    
    print("βœ“ Clarification attempt limits work correctly")


def test_referral_urgency_determination():
    """Test referral urgency determination based on context."""
    print("Testing referral urgency determination...")
    
    processor = ConsentResponseProcessor()
    
    # Test urgent context
    urgent_context = {
        'message_content': 'I am in crisis and need immediate help',
        'distress_level': 'high'
    }
    urgent_urgency = processor._determine_referral_urgency(urgent_context)
    assert urgent_urgency == ReferralUrgency.URGENT
    
    # Test high urgency context
    high_context = {
        'message_content': 'I am struggling with significant distress',
        'distress_level': 'high'
    }
    high_urgency = processor._determine_referral_urgency(high_context)
    assert high_urgency == ReferralUrgency.HIGH
    
    # Test medium urgency context
    medium_context = {
        'message_content': 'I am feeling overwhelmed',
        'distress_level': 'medium'
    }
    medium_urgency = processor._determine_referral_urgency(medium_context)
    assert medium_urgency == ReferralUrgency.MEDIUM
    
    # Test low urgency context
    low_context = {
        'message_content': 'I could use some support',
        'distress_level': 'low'
    }
    low_urgency = processor._determine_referral_urgency(low_context)
    assert low_urgency == ReferralUrgency.LOW
    
    print("βœ“ Referral urgency determination works correctly")


def test_follow_up_delay_calculation():
    """Test follow-up delay calculation based on attempts."""
    print("Testing follow-up delay calculation...")
    
    processor = ConsentResponseProcessor()
    
    # Test first attempt delay
    first_delay = processor._get_follow_up_delay(0)
    assert first_delay == 24  # 24 hours for first attempt
    
    # Test second attempt delay
    second_delay = processor._get_follow_up_delay(1)
    assert second_delay == 72  # 72 hours for second attempt
    
    # Test final attempt delay
    final_delay = processor._get_follow_up_delay(2)
    assert final_delay == 168  # 168 hours (1 week) for final attempt
    
    # Test beyond limit
    beyond_delay = processor._get_follow_up_delay(5)
    assert beyond_delay == 168  # Should use final attempt delay
    
    print("βœ“ Follow-up delay calculation works correctly")


def test_processing_statistics():
    """Test processing statistics generation."""
    print("Testing processing statistics...")
    
    processor = ConsentResponseProcessor()
    
    # Create test interaction history
    interactions = [
        ConsentInteraction(
            interaction_id="stat_1",
            message_type=ConsentMessageType.INITIAL_REQUEST,
            message_content="Initial request",
            patient_response="Yes",
            response_classification=ConsentResponse.ACCEPT,
            timestamp=datetime.now(),
            session_id="stat_session",
            clarification_attempts=0
        ),
        ConsentInteraction(
            interaction_id="stat_2",
            message_type=ConsentMessageType.CLARIFICATION,
            message_content="Clarification",
            patient_response="Maybe",
            response_classification=ConsentResponse.AMBIGUOUS,
            timestamp=datetime.now(),
            session_id="stat_session",
            requires_clarification=True,
            clarification_attempts=1
        ),
        ConsentInteraction(
            interaction_id="stat_3",
            message_type=ConsentMessageType.DECLINE_ACKNOWLEDGMENT,
            message_content="Acknowledgment",
            patient_response="No",
            response_classification=ConsentResponse.DECLINE,
            timestamp=datetime.now(),
            session_id="stat_session",
            clarification_attempts=0
        )
    ]
    
    # Generate statistics
    stats = processor.get_processing_statistics(interactions)
    
    # Verify statistics structure
    required_fields = ['total_interactions', 'response_type_counts', 'message_type_counts',
                      'successful_resolutions', 'resolution_rate', 'clarification_rate',
                      'average_clarification_attempts']
    for field in required_fields:
        assert field in stats, f"Statistics missing required field: {field}"
    
    # Verify counts
    assert stats['total_interactions'] == 3
    assert stats['response_type_counts']['accept'] == 1
    assert stats['response_type_counts']['decline'] == 1
    assert stats['response_type_counts']['ambiguous'] == 1
    
    # Verify rates
    assert stats['successful_resolutions'] == 2  # Accept + Decline
    assert stats['resolution_rate'] == 2/3  # 2 out of 3
    assert stats['clarification_rate'] == 1/3  # 1 out of 3
    
    # Test empty interactions
    empty_stats = processor.get_processing_statistics([])
    assert empty_stats['total_interactions'] == 0
    
    print("βœ“ Processing statistics work correctly")


def test_unclear_response_processing():
    """Test processing of unclear patient responses."""
    print("Testing unclear response processing...")
    
    processor = ConsentResponseProcessor()
    
    # Test unclear response (something that doesn't match any pattern)
    unclear_response = "Banana elephant purple"
    context = {'distress_level': 'medium'}
    
    result = processor.process_patient_response(unclear_response, "test_session_5", context)
    
    # Verify result structure
    assert result.action == ProcessingAction.REQUEST_CLARIFICATION
    assert result.generate_provider_summary == False
    assert result.log_referral == False
    assert result.requires_follow_up == True
    
    # Verify interaction record
    interaction = result.interaction_record
    assert interaction.patient_response == unclear_response
    assert interaction.response_classification == ConsentResponse.UNCLEAR
    assert interaction.message_type == ConsentMessageType.CLARIFICATION
    assert interaction.requires_clarification == True
    
    # Verify clarification message is general
    assert len(result.message) > 0
    assert 'understand your preferences' in result.message.lower()
    
    # Verify context updates
    assert result.context_updates['consent_status'] == 'unclear_response'
    assert result.context_updates['response_clarity_issues'] == True
    
    print("βœ“ Unclear response processing works correctly")


def test_processing_result_serialization():
    """Test ProcessingResult serialization."""
    print("Testing ProcessingResult serialization...")
    
    processor = ConsentResponseProcessor()
    
    # Process a response to get a result
    result = processor.process_patient_response("Yes, please", "test_session_6")
    
    # Test serialization
    result_dict = result.to_dict()
    
    # Verify serialized structure
    required_fields = ['action', 'message', 'generate_provider_summary', 'log_referral',
                      'referral_urgency', 'requires_follow_up', 'follow_up_delay_hours',
                      'interaction_record', 'next_steps', 'context_updates']
    for field in required_fields:
        assert field in result_dict, f"Serialized result missing field: {field}"
    
    # Verify data types
    assert isinstance(result_dict['action'], str)
    assert isinstance(result_dict['message'], str)
    assert isinstance(result_dict['generate_provider_summary'], bool)
    assert isinstance(result_dict['next_steps'], list)
    assert isinstance(result_dict['context_updates'], dict)
    assert isinstance(result_dict['interaction_record'], dict)
    
    print("βœ“ ProcessingResult serialization works correctly")


def main():
    """Run all consent response processor tests."""
    print("=" * 60)
    print("CONSENT RESPONSE PROCESSOR TESTS")
    print("=" * 60)
    
    tests = [
        test_consent_response_processor_initialization,
        test_acceptance_processing,
        test_decline_processing,
        test_ambiguous_response_processing,
        test_clarification_attempt_limits,
        test_referral_urgency_determination,
        test_follow_up_delay_calculation,
        test_processing_statistics,
        test_unclear_response_processing,
        test_processing_result_serialization
    ]
    
    passed = 0
    failed = 0
    
    for test in tests:
        try:
            print(f"\n{test.__name__.replace('_', ' ').title()}:")
            print("-" * 40)
            
            test()  # Just call the test, don't expect return value
            passed += 1
            print("βœ“ PASSED")
                
        except Exception as e:
            failed += 1
            print(f"βœ— FAILED: {str(e)}")
    
    print("\n" + "=" * 60)
    print(f"RESULTS: {passed} passed, {failed} failed")
    print("=" * 60)
    
    if failed == 0:
        print("πŸŽ‰ All consent response processor tests passed!")
        print("\n**Task 5.3: Enhanced Consent Response Processing**")
        print("βœ“ COMPLETED: Patient decline handling with medical dialogue return")
        print("βœ“ COMPLETED: Acceptance processing with referral generation")
        print("βœ“ COMPLETED: Ambiguous response clarification workflow")
        print("βœ“ COMPLETED: Referral urgency determination")
        print("βœ“ COMPLETED: Clarification attempt limits and escalation")
        print("βœ“ VALIDATED: Requirements 4.2, 4.3, 4.4")
        return True
    else:
        print("❌ Some tests failed. Please check the implementation.")
        return False


if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)