"""Unit coverage for SPEC-008 (CFG-01..03).""" import unittest from unittest.mock import mock_open, patch import toml from fjerkroa_bot import FjerkroaBot from fjerkroa_bot.ai_responder import AIMessage, AIResponder class TestConfigLoad(unittest.TestCase): def test_load_config_parses_toml(self): """CFG-01: load_config parses the TOML file into a plain dict.""" data = {"system": "prompt", "history-limit": 7, "additional-responders": []} with patch("builtins.open", mock_open(read_data=toml.dumps(data))): result = FjerkroaBot.load_config("config.toml") self.assertEqual(result, data) class TestPerChannelPrompt(unittest.TestCase): def test_channel_override_wins(self): """CFG-02: responder bound to a channel uses config[channel] over config['system'].""" config = {"system": "Default prompt", "kitchen": "Kitchen prompt", "history-limit": 5} responder = AIResponder(config, "kitchen") system = responder.message(AIMessage("alice", "hei", "kitchen"))[0]["content"] self.assertTrue(system.startswith("Kitchen prompt")) def test_fallback_to_system(self): """CFG-02: without a channel key the shared system prompt is used.""" config = {"system": "Default prompt", "history-limit": 5} responder = AIResponder(config, "kitchen") system = responder.message(AIMessage("alice", "hei", "kitchen"))[0]["content"] self.assertTrue(system.startswith("Default prompt")) class TestNewsFileMissing(unittest.TestCase): def test_missing_news_file_keeps_placeholder(self): """CFG-03: nonexistent news file -> {news} placeholder stays literal, no crash.""" config = {"system": "N: {news}", "history-limit": 5, "news": "/nonexistent/news.txt"} responder = AIResponder(config, "chat") system = responder.message(AIMessage("alice", "hei"))[0]["content"] self.assertIn("{news}", system)