File size: 7,151 Bytes
d7228c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Unit tests for LawSLM Chat Engine:
- IntentDetector: classifies user prompts into correct intent categories
- KnowledgeEngine: generates natural, dynamic responses (no generic templates)
- ConversationMemory: tracks multi-turn history and resolves coreferences
- ResponseValidator: validates quality and rejects template artifacts
"""

import pytest
from slm.chat.intent import IntentDetector, KnowledgeEngine, IntentType
from slm.chat.memory import ConversationMemory
from slm.chat.validator import ResponseValidator


class TestIntentDetector:
    def test_identity(self):
        assert IntentDetector.detect_intent("Who created you?") == IntentType.IDENTITY
        assert IntentDetector.detect_intent("who made you") == IntentType.IDENTITY

    def test_about_self(self):
        assert IntentDetector.detect_intent("Who are you?") == IntentType.ABOUT_SELF
        assert IntentDetector.detect_intent("Tell me about yourself") == IntentType.ABOUT_SELF
        assert IntentDetector.detect_intent("What can you do?") == IntentType.ABOUT_SELF

    def test_greeting(self):
        assert IntentDetector.detect_intent("Hello") == IntentType.GREETING
        assert IntentDetector.detect_intent("hi") == IntentType.GREETING

    def test_thanks(self):
        assert IntentDetector.detect_intent("Thank you") == IntentType.THANKS
        assert IntentDetector.detect_intent("thanks") == IntentType.THANKS

    def test_farewell(self):
        assert IntentDetector.detect_intent("goodbye") == IntentType.FAREWELL

    def test_pdf_generation(self):
        assert IntentDetector.detect_intent("Generate a PDF report") == IntentType.PDF_GENERATION

    def test_legal(self):
        assert IntentDetector.detect_intent("Explain Section 420 IPC") == IntentType.LEGAL

    def test_programming(self):
        assert IntentDetector.detect_intent("Write Python code for sorting") == IntentType.PROGRAMMING

    def test_finance(self):
        assert IntentDetector.detect_intent("Calculate loan interest for 10 lakh at 12%") == IntentType.FINANCE

    def test_math(self):
        assert IntentDetector.detect_intent("Calculate 25 * 4 + 10") == IntentType.MATH

    def test_science(self):
        assert IntentDetector.detect_intent("Explain photosynthesis") == IntentType.SCIENCE


class TestKnowledgeEngine:
    def test_identity_response_mentions_amit(self):
        result = KnowledgeEngine.generate_response("Who created you?", IntentType.IDENTITY)
        assert "Amit Kumar" in result["content"]
        assert result["has_pdf"] is False

    def test_about_self_response(self):
        result = KnowledgeEngine.generate_response("Who are you?", IntentType.ABOUT_SELF)
        assert "LawSLM" in result["content"]

    def test_greeting_response_is_natural(self):
        result = KnowledgeEngine.generate_response("Hello", IntentType.GREETING)
        assert "Hello" in result["content"]
        # Must NOT contain generic template phrases
        assert "Analysis & Assistance" not in result["content"]
        assert "Core Concept" not in result["content"]

    def test_thanks_response(self):
        result = KnowledgeEngine.generate_response("Thank you", IntentType.THANKS)
        assert "welcome" in result["content"].lower()

    def test_pdf_has_metadata(self):
        result = KnowledgeEngine.generate_response("Generate PDF report", IntentType.PDF_GENERATION)
        assert result["has_pdf"] is True
        assert result["pdf_meta"] is not None

    def test_finance_with_numbers(self):
        result = KnowledgeEngine.generate_response(
            "Calculate loan interest for 100000 at 12% for 2 years", IntentType.FINANCE
        )
        assert "₹" in result["content"] or "Interest" in result["content"]

    def test_math_calculation(self):
        result = KnowledgeEngine.generate_response("Calculate 25 * 4 + 10", IntentType.MATH)
        content = result["content"]
        assert "110" in content  # 25*4+10 = 110

    def test_legal_section_420(self):
        result = KnowledgeEngine.generate_response("Explain Section 420 IPC", IntentType.LEGAL)
        assert "420" in result["content"]
        assert "cheat" in result["content"].lower() or "Cheating" in result["content"]

    def test_python_explanation(self):
        result = KnowledgeEngine.generate_response("What is Python?", IntentType.GENERAL_QA)
        assert "Python" in result["content"]

    def test_no_generic_template_in_any_response(self):
        """Verify no response uses banned template phrases."""
        test_prompts = [
            ("Hello", IntentType.GREETING),
            ("Who are you?", IntentType.ABOUT_SELF),
            ("Explain gravity", IntentType.SCIENCE),
            ("Write Python code", IntentType.PROGRAMMING),
        ]
        banned = ["Analysis & Assistance", "Core Concept", "Key Consideration"]
        for prompt, intent in test_prompts:
            result = KnowledgeEngine.generate_response(prompt, intent)
            for phrase in banned:
                assert phrase not in result["content"], (
                    f"Banned phrase '{phrase}' found in response to '{prompt}'"
                )


class TestConversationMemory:
    def test_add_and_retrieve(self):
        mem = ConversationMemory()
        mem.add_message("user", "Hello")
        mem.add_message("assistant", "Hi! How can I help?")
        history = mem.get_history()
        assert len(history) == 2
        assert history[0]["role"] == "user"
        assert history[1]["role"] == "assistant"

    def test_coreference_resolution(self):
        mem = ConversationMemory()
        mem.add_message("user", "What is Python?")
        mem.add_message("assistant", "Python is a programming language.")
        resolved = mem.resolve_coreference("Tell me more about this")
        assert "python" in resolved.lower() or "this" in resolved.lower()


class TestResponseValidator:
    def test_valid_text_passes(self):
        is_valid, cleaned = ResponseValidator.validate_response("Hello! I am LawSLM.")
        assert is_valid is True
        assert "LawSLM" in cleaned

    def test_empty_text_fails(self):
        is_valid, _ = ResponseValidator.validate_response("")
        assert is_valid is False

    def test_unk_tokens_removed(self):
        is_valid, cleaned = ResponseValidator.validate_response("Hello <unk> world <pad>")
        assert is_valid is True
        assert "<unk>" not in cleaned
        assert "<pad>" not in cleaned

    def test_repetitive_loop_cleaned(self):
        is_valid, cleaned = ResponseValidator.validate_response("the the the the the answer")
        assert is_valid is True
        assert cleaned.count("the") < 4

    def test_template_phrases_stripped(self):
        is_valid, cleaned = ResponseValidator.validate_response(
            "Analysis & Assistance\n\nHello, I am LawSLM."
        )
        assert is_valid is True
        assert "Analysis & Assistance" not in cleaned

    def test_unbalanced_code_fence_fixed(self):
        is_valid, cleaned = ResponseValidator.validate_response("```python\nprint('hello')")
        assert is_valid is True
        assert cleaned.count("```") % 2 == 0