test-resolve_party.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/env python3
  2. # /// script
  3. # requires-python = ">=3.11"
  4. # ///
  5. """Unit tests for resolve_party.py — merge, alias, override, group resolution."""
  6. import sys
  7. import unittest
  8. from pathlib import Path
  9. sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  10. import resolve_party as rp # noqa: E402
  11. AGENTS = {
  12. "bmad-agent-analyst": {"name": "Mary", "icon": "📊", "title": "Analyst"},
  13. "bmad-agent-pm": {"name": "John", "icon": "📋", "title": "PM"},
  14. }
  15. class TestAlias(unittest.TestCase):
  16. def test_strips_known_prefixes(self):
  17. self.assertEqual(rp._alias("bmad-agent-analyst"), "analyst")
  18. self.assertEqual(rp._alias("bmad-foo"), "foo")
  19. def test_passes_through_unprefixed(self):
  20. self.assertEqual(rp._alias("morpheus"), "morpheus")
  21. class TestBuildCollective(unittest.TestCase):
  22. def test_installed_agents_indexed_by_code_alias_and_name(self):
  23. col, idx, _ = rp.build_collective(AGENTS, [])
  24. self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
  25. self.assertEqual(idx["analyst"], "bmad-agent-analyst") # alias
  26. self.assertEqual(idx["mary"], "bmad-agent-analyst") # name (ci)
  27. self.assertEqual(idx["bmad-agent-pm"], "bmad-agent-pm") # full code
  28. self.assertEqual(col["bmad-agent-analyst"]["source"], "installed")
  29. def test_custom_member_appends(self):
  30. col, _, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus", "persona": "riddles"}])
  31. self.assertIn("morpheus", col)
  32. self.assertEqual(col["morpheus"]["source"], "custom")
  33. self.assertEqual(col["morpheus"]["persona"], "riddles")
  34. def test_custom_overrides_installed_by_alias(self):
  35. col, _, _ = rp.build_collective(AGENTS, [{"code": "analyst", "name": "Mary-Custom", "persona": "p"}])
  36. # Override lands on the canonical installed code, not a new "analyst" entry.
  37. self.assertNotIn("analyst", col)
  38. self.assertEqual(col["bmad-agent-analyst"]["source"], "custom")
  39. self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
  40. def test_member_without_code_skipped(self):
  41. col, _, _ = rp.build_collective(AGENTS, [{"name": "Nameless"}])
  42. self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
  43. class TestResolveMembers(unittest.TestCase):
  44. def setUp(self):
  45. self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
  46. def test_resolves_in_listed_order_and_flags_unknowns(self):
  47. resolved, unresolved = rp.resolve_members(["morpheus", "analyst", "ghost"], self.col, self.idx)
  48. self.assertEqual([m["code"] for m in resolved], ["morpheus", "bmad-agent-analyst"])
  49. self.assertEqual(unresolved, ["ghost"])
  50. def test_empty(self):
  51. self.assertEqual(rp.resolve_members([], self.col, self.idx), ([], []))
  52. class TestGroups(unittest.TestCase):
  53. GROUPS = [
  54. {"id": "wr", "name": "Writers", "members": ["analyst", "morpheus"]},
  55. {"id": "bad"}, # no name -> falls back to id; no members -> count 0
  56. {"name": "no-id"}, # dropped from menu
  57. ]
  58. def test_menu_is_names_only_with_counts_and_open_cast_flag(self):
  59. menu = rp.group_menu(self.GROUPS)
  60. self.assertEqual(menu, [
  61. {"id": "wr", "name": "Writers", "member_count": 2},
  62. {"id": "bad", "name": "bad", "member_count": 0, "open_cast": True},
  63. ])
  64. def test_find_group(self):
  65. self.assertEqual(rp.find_group(self.GROUPS, "wr")["name"], "Writers")
  66. self.assertIsNone(rp.find_group(self.GROUPS, "missing"))
  67. class TestGroupDetail(unittest.TestCase):
  68. def setUp(self):
  69. self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
  70. def test_scene_passes_through_when_present(self):
  71. g = {"id": "tos-10-forward", "name": "Ten Forward", "members": ["morpheus"],
  72. "scene": "Late evening, a few rounds in."}
  73. d = rp.group_detail(g, self.col, self.idx)
  74. self.assertEqual(d["scene"], "Late evening, a few rounds in.")
  75. self.assertEqual([m["code"] for m in d["members"]], ["morpheus"])
  76. def test_scene_omitted_when_absent_or_empty(self):
  77. for g in ({"id": "g", "members": ["morpheus"]},
  78. {"id": "g", "members": ["morpheus"], "scene": ""}):
  79. self.assertNotIn("scene", rp.group_detail(g, self.col, self.idx))
  80. def test_anchored_group_is_not_open_cast(self):
  81. g = {"id": "g", "members": ["morpheus"]}
  82. self.assertNotIn("open_cast", rp.group_detail(g, self.col, self.idx))
  83. def test_open_cast_group_flagged_with_empty_members(self):
  84. g = {"id": "rebels", "name": "Star Wars Rebels",
  85. "scene": "Figures from the Rebels universe drop in as the topic calls for them."}
  86. d = rp.group_detail(g, self.col, self.idx)
  87. self.assertTrue(d["open_cast"])
  88. self.assertEqual(d["members"], [])
  89. self.assertEqual(d["scene"][:7], "Figures")
  90. def test_memory_enabled_follows_group_flag_and_defaults_off(self):
  91. on = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": True}, self.col, self.idx)
  92. self.assertTrue(on["memory_enabled"])
  93. off = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": False}, self.col, self.idx)
  94. self.assertFalse(off["memory_enabled"])
  95. absent = rp.group_detail({"id": "g", "members": ["morpheus"]}, self.col, self.idx)
  96. self.assertFalse(absent["memory_enabled"]) # opt-in per named group
  97. class TestInstalledCodesIsDefaultRoom(unittest.TestCase):
  98. """The default room is installed agents only; pure customs stay in the pool."""
  99. def test_pure_custom_excluded_override_kept_in_default_room(self):
  100. col, _, installed = rp.build_collective(AGENTS, [
  101. {"code": "morpheus", "name": "Morpheus"}, # pure custom
  102. {"code": "analyst", "name": "Mary-Custom", "persona": "p"}, # override
  103. {"code": "sec-hawk", "name": "Vex"}, # shipped crew member
  104. ])
  105. # Pure customs are in the pool...
  106. self.assertIn("morpheus", col)
  107. self.assertIn("sec-hawk", col)
  108. # ...but NOT in the default room.
  109. self.assertEqual(installed, ["bmad-agent-analyst", "bmad-agent-pm"])
  110. default_room = [col[c]["code"] for c in installed]
  111. self.assertEqual(default_room, ["bmad-agent-analyst", "bmad-agent-pm"])
  112. # An override keeps its installed slot (and its custom content).
  113. self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
  114. if __name__ == "__main__":
  115. unittest.main()