"""tests/test_atelier_mcp.py — REQ-225. Covers: tool registration (all 4 tools discoverable), lookup_principle returns the principle text + core C-rule, validate_against_principles catches a planted C1 (correctness) + C7 (observability) violation in a known-bad snippet and passes a known-good snippet, matrix_lookup returns the domain→core mapping, plugin discovery loads all plugins in plugins/. """ import os import sys import unittest sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mcp.atelier.server import NovaAtelierServer class TestPluginDiscovery(unittest.TestCase): def setUp(self): self.server = NovaAtelierServer() self.loaded = self.server.load_plugins() def test_both_plugins_loaded(self): self.assertIn("principles", self.loaded) self.assertIn("validation", self.loaded) def test_four_tools_registered(self): tools = self.server.list_tools() names = {t["name"] for t in tools} self.assertIn("atelier_lookup_principle", names) self.assertIn("atelier_list_domains", names) self.assertIn("atelier_matrix_lookup", names) self.assertIn("atelier_validate_against_principles", names) self.assertEqual(len(names), 4) class TestLookupPrinciple(unittest.TestCase): def setUp(self): self.server = NovaAtelierServer() self.server.load_plugins() def test_lookup_security_p4(self): result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P4"}) self.assertNotIn("error", result) self.assertEqual(result["domain"], "security") self.assertEqual(result["principle_id"], "P4") self.assertIn("Secrets", result["title"]) self.assertIn("C1", result["core_c_rule"]) self.assertIn("C7", result["core_c_rule"]) def test_lookup_security_p1(self): result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P1"}) self.assertNotIn("error", result) self.assertIn("Boundary", result["title"]) def test_lookup_unknown_domain(self): result = self.server.call_tool("atelier_lookup_principle", {"domain": "nonexistent", "principle_id": "P1"}) self.assertIn("error", result) def test_lookup_unknown_principle(self): result = self.server.call_tool("atelier_lookup_principle", {"domain": "security", "principle_id": "P99"}) self.assertIn("error", result) class TestListDomains(unittest.TestCase): def setUp(self): self.server = NovaAtelierServer() self.server.load_plugins() def test_returns_19_domains(self): result = self.server.call_tool("atelier_list_domains", {}) self.assertEqual(len(result), 19) def test_security_is_nova_relevant(self): result = self.server.call_tool("atelier_list_domains", {}) sec = next(d for d in result if d["domain"] == "security") self.assertTrue(sec["nova_relevant"]) def test_ui_ux_not_nova_relevant(self): result = self.server.call_tool("atelier_list_domains", {}) ui = next(d for d in result if d["domain"] == "ui-ux") self.assertFalse(ui["nova_relevant"]) class TestMatrixLookup(unittest.TestCase): def setUp(self): self.server = NovaAtelierServer() self.server.load_plugins() def test_security_matrix(self): result = self.server.call_tool("atelier_matrix_lookup", {"domain": "security"}) self.assertEqual(result["domain"], "security") self.assertEqual(len(result["mapping"]), 10) p4 = next(m for m in result["mapping"] if m["p"] == "P4") self.assertIn("C1", p4["core"]) self.assertIn("C7", p4["core"]) def test_unknown_domain_matrix(self): result = self.server.call_tool("atelier_matrix_lookup", {"domain": "nonexistent"}) self.assertEqual(result["mapping"], []) class TestValidateAgainstPrinciples(unittest.TestCase): def setUp(self): self.server = NovaAtelierServer() self.server.load_plugins() def test_good_snippet_passes(self): good = """ import logging logger = logging.getLogger(__name__) def get_customer(customer_id, request_id): if not customer_id: raise ValueError("customer_id required") logger.info("fetching customer %s (request %s)", customer_id, request_id) return db.query(customer_id) """ result = self.server.call_tool("atelier_validate_against_principles", {"snippet": good}) # Should not have FAIL on secrets (no hardcoded secrets) sec_checks = [r for r in result["results"] if r["check_id"].startswith("SEC.1")] for c in sec_checks: self.assertEqual(c["status"], "PASS", f"SEC.1 should PASS: {c}") def test_bad_snippet_catches_secret(self): bad = """ api_key = "sk-1234567890abcdef" def get_data(): pass """ result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad}) # SEC.1 (secrets in code) should FAIL sec1 = next(r for r in result["results"] if r["check_id"] == "SEC.1") self.assertEqual(sec1["status"], "FAIL") def test_bad_snippet_catches_swallowed_error(self): bad = """ try: do_something() except: pass """ result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad}) # C1.2 (handles failure cases) should FAIL because of `except: pass` c12 = next(r for r in result["results"] if r["check_id"] == "C1.2") self.assertEqual(c12["status"], "FAIL") def test_bad_snippet_catches_obfuscated_names(self): bad = """ def doStuff(data, temp, x): return data + temp + x """ result = self.server.call_tool("atelier_validate_against_principles", {"snippet": bad}) # C2.1 (names intent-revealing) should FAIL c21 = next(r for r in result["results"] if r["check_id"] == "C2.1") self.assertEqual(c21["status"], "FAIL") def test_result_structure(self): result = self.server.call_tool("atelier_validate_against_principles", {"snippet": "x = 1"}) self.assertIn("overall", result) self.assertIn("results", result) self.assertIsInstance(result["results"], list) self.assertGreater(len(result["results"]), 0) if __name__ == "__main__": unittest.main()