# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Tests for CommCoach AI service (prompt building and response parsing). These tests don't require AI calls -- they test the prompt construction and JSON parsing. """ import pytest import json from ..serviceCommcoachAi import ( buildCoachingSystemPrompt, buildSummaryPrompt, buildScoringPrompt, buildTaskExtractionPrompt, buildEarlierConversationSummaryPrompt, prepareMessagesForPrompt, parseJsonResponse, ) class TestBuildCoachingSystemPrompt: def test_basicPrompt(self): context = {"title": "Conflict Resolution", "category": "conflict"} prompt = buildCoachingSystemPrompt(context, [], []) assert "Conflict Resolution" in prompt assert "conflict" in prompt assert "coach" in prompt.lower() def test_withGoals(self): context = { "title": "Leadership", "category": "leadership", "goals": json.dumps([{"text": "Improve delegation"}]), } prompt = buildCoachingSystemPrompt(context, [], []) assert "Improve delegation" in prompt def test_withInsights(self): context = { "title": "Test", "category": "custom", "insights": json.dumps([{"text": "User shows progress in empathy"}]), } prompt = buildCoachingSystemPrompt(context, [], []) assert "empathy" in prompt def test_withPreviousMessages(self): context = {"title": "Test", "category": "custom"} messages = [ {"role": "user", "content": "I had a conflict with my team"}, {"role": "assistant", "content": "Tell me more about that"}, ] prompt = buildCoachingSystemPrompt(context, messages, []) assert "conflict" in prompt.lower() def test_withTasks(self): context = {"title": "Test", "category": "custom"} tasks = [ {"title": "Practice listening", "status": "open"}, {"title": "Read book", "status": "done"}, ] prompt = buildCoachingSystemPrompt(context, [], tasks) assert "Practice listening" in prompt def test_promptLanguageIsGerman(self): context = {"title": "Test", "category": "custom"} prompt = buildCoachingSystemPrompt(context, [], []) assert "Führungskräfte" in prompt or "Coach" in prompt def test_withEarlierSummary(self): context = {"title": "Test", "category": "custom"} messages = [{"role": "user", "content": "Recent question"}] earlierSummary = "User discussed delegation. Coach suggested practice." prompt = buildCoachingSystemPrompt(context, messages, [], earlierSummary=earlierSummary) assert "Älterer Gesprächsverlauf" in prompt assert "delegation" in prompt.lower() assert "Recent question" in prompt def test_withRollingOverview(self): context = {"title": "Test", "category": "custom"} prompt = buildCoachingSystemPrompt( context, [], [], rollingOverview="User arbeitet an Delegation. Fortschritt sichtbar." ) assert "Gesamtüberblick" in prompt assert "Delegation" in prompt def test_withRetrievedSession(self): context = {"title": "Test", "category": "custom"} retrieved = {"summary": "Delegation und Feedback besprochen", "startedAt": "2026-02-01T10:00:00Z"} prompt = buildCoachingSystemPrompt(context, [], [], retrievedSession=retrieved) assert "angefragte Session" in prompt assert "Delegation" in prompt class TestPrepareMessagesForPrompt: def test_underThreshold(self): messages = [{"role": "user", "content": f"msg {i}"} for i in range(10)] earlier, recent = prepareMessagesForPrompt(messages, None, None) assert earlier is None assert len(recent) == 10 def test_overThresholdWithCachedSummary(self): messages = [{"role": "user", "content": f"msg {i}"} for i in range(40)] cached = "Summary of first 25 messages" earlier, recent = prepareMessagesForPrompt(messages, cached, 25) assert earlier == cached assert len(recent) == 15 def test_overThresholdNeedsRegenerate(self): messages = [{"role": "user", "content": f"msg {i}"} for i in range(40)] earlier, recent = prepareMessagesForPrompt(messages, "old summary", 20) assert earlier is None assert len(recent) == 40 class TestBuildEarlierConversationSummaryPrompt: def test_basic(self): messages = [ {"role": "user", "content": "I have a conflict"}, {"role": "assistant", "content": "Tell me more"}, ] prompt = buildEarlierConversationSummaryPrompt(messages) assert "Fasse" in prompt assert "conflict" in prompt class TestBuildSummaryPrompt: def test_basic(self): messages = [ {"role": "user", "content": "I need help with delegation"}, {"role": "assistant", "content": "Let's work on that"}, ] prompt = buildSummaryPrompt(messages, "Delegation") assert "Delegation" in prompt assert "Zusammenfassung" in prompt def test_emptyMessages(self): prompt = buildSummaryPrompt([], "Test") assert "Test" in prompt class TestBuildScoringPrompt: def test_basic(self): messages = [{"role": "user", "content": "I tried active listening today"}] prompt = buildScoringPrompt(messages, "leadership") assert "empathy" in prompt assert "clarity" in prompt assert "JSON" in prompt def test_containsScaleInfo(self): prompt = buildScoringPrompt([{"role": "user", "content": "test"}], "custom") assert "0-100" in prompt class TestBuildTaskExtractionPrompt: def test_basic(self): messages = [ {"role": "assistant", "content": "You should try practicing active listening this week"}, ] prompt = buildTaskExtractionPrompt(messages) assert "JSON" in prompt assert "Aufgaben" in prompt or "Aufgabe" in prompt def test_limitedMessages(self): messages = [{"role": "user", "content": f"msg {i}"} for i in range(35)] prompt = buildTaskExtractionPrompt(messages) assert "msg 34" in prompt assert "msg 0" not in prompt class TestParseJsonResponse: def test_validJson(self): result = parseJsonResponse('[{"dimension": "empathy", "score": 70}]') assert isinstance(result, list) assert result[0]["score"] == 70 def test_codeBlockWrapped(self): result = parseJsonResponse('```json\n[{"title": "task1"}]\n```') assert isinstance(result, list) assert result[0]["title"] == "task1" def test_invalidJson(self): result = parseJsonResponse('not json at all', fallback=[]) assert result == [] def test_emptyString(self): result = parseJsonResponse('', fallback=None) assert result is None def test_nestedCodeBlock(self): text = '```\n{"key": "value"}\n```' result = parseJsonResponse(text) assert result["key"] == "value"