"""U-029 tests: c_skill_diff + list/get read helpers for v_skill_library / v_skill_audit_log. Real sqlite + real git in a throwaway temp repo (never graphlemon's own -- same reasoning as test_skill_update.py). Run: python3 -m unittest src.test_skill_query -v """ import subprocess import tempfile import unittest from src import schema, skill_query, skill_update def _init_git_repo(path): subprocess.run(["git", "init"], cwd=path, check=True, capture_output=True) class SkillQueryTestBase(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) _init_git_repo(self.tmp.name) self.conn = schema.connect(":memory:") schema.create_schema(self.conn) self.conn.commit() def tearDown(self): self.conn.close() def _insert_skill(self, skill_id, owner_org_node, source="new", migrated_from_profile=None): self.conn.execute( "INSERT INTO skill (skill_id, owner_org_node, file_path, current_git_commit_sha, source, " "migrated_from_profile, status) VALUES (?, ?, ?, 'unknown', ?, ?, 'active')", (skill_id, owner_org_node, "skills/" + skill_id, source, migrated_from_profile), ) self.conn.commit() class ListSkillsTest(SkillQueryTestBase): def test_lists_all_skills(self): self._insert_skill("s1", "planner") self._insert_skill("s2", "coder") result = skill_query.list_skills(self.conn) self.assertEqual({s["skill_id"] for s in result}, {"s1", "s2"}) def test_includes_owner_org_node_and_source(self): self._insert_skill("s1", "validator", source="migrated_from_hermes", migrated_from_profile="qa") result = skill_query.list_skills(self.conn) self.assertEqual(result[0]["owner_org_node"], "validator") self.assertEqual(result[0]["source"], "migrated_from_hermes") self.assertEqual(result[0]["migrated_from_profile"], "qa") def test_empty_returns_empty_list(self): self.assertEqual(skill_query.list_skills(self.conn), []) class GetSkillAuditLogTest(SkillQueryTestBase): def test_nonexistent_skill_raises(self): with self.assertRaises(skill_query.SkillNotFoundError): skill_query.get_skill_audit_log(self.conn, "no-such-skill") def test_skill_with_no_iterations_returns_empty_list(self): self._insert_skill("s1", "planner") self.assertEqual(skill_query.get_skill_audit_log(self.conn, "s1"), []) def test_returns_iterations_oldest_first(self): self._insert_skill("s1", "coder") self.conn.execute( "INSERT INTO bug_record (bug_id, source, description, root_cause_category, root_cause_detail, " "suggested_route, status) VALUES ('bug-1', 'validator', 'x', 'skill_defect', 'd', 'fast_lane', 'routed')" ) self.conn.execute( "INSERT INTO skill_iteration (iteration_id, skill_id, triggered_by_bug_id, before_git_commit_sha, " "after_git_commit_sha, change_summary, applied_at) VALUES " "('it-1', 's1', 'bug-1', 'sha0', 'sha1', 'fix A', '2026-07-01 00:00:00')" ) self.conn.execute( "INSERT INTO skill_iteration (iteration_id, skill_id, triggered_by_bug_id, before_git_commit_sha, " "after_git_commit_sha, change_summary, applied_at) VALUES " "('it-2', 's1', 'bug-1', 'sha1', 'sha2', 'fix B', '2026-07-02 00:00:00')" ) self.conn.commit() result = skill_query.get_skill_audit_log(self.conn, "s1") self.assertEqual([r["iteration_id"] for r in result], ["it-1", "it-2"]) self.assertEqual(result[0]["change_summary"], "fix A") class GetDiffTest(SkillQueryTestBase): def test_diff_between_two_commits_shows_content_change(self): before_sha = skill_update._write_and_commit(self.tmp.name, "skills/s1/SKILL.md", "v1 content\n", "seed") after_sha = skill_update._write_and_commit(self.tmp.name, "skills/s1/SKILL.md", "v2 content\n", "update") diff_text = skill_query.get_diff(before_sha, after_sha, repo_path=self.tmp.name) self.assertIn("-v1 content", diff_text) self.assertIn("+v2 content", diff_text) def test_identical_commits_produce_empty_diff(self): sha = skill_update._write_and_commit(self.tmp.name, "skills/s1/SKILL.md", "same\n", "seed") diff_text = skill_query.get_diff(sha, sha, repo_path=self.tmp.name) self.assertEqual(diff_text, "") if __name__ == "__main__": unittest.main()