840e5fc5af
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: abdoelsayed2016 <27821589+abdoelsayed2016@users.noreply.github.com>
199 lines
8.3 KiB
Python
199 lines
8.3 KiB
Python
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from src.command_graph import CommandGraph, build_command_graph
|
|
from src.models import PortingModule
|
|
|
|
|
|
def _module(name: str, source_hint: str) -> PortingModule:
|
|
return PortingModule(name=name, responsibility="stub", source_hint=source_hint)
|
|
|
|
|
|
class CommandGraphTests(unittest.TestCase):
|
|
# -- construction & immutability ------------------------------------------
|
|
|
|
def test_empty_graph(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
self.assertEqual(graph.builtins, ())
|
|
self.assertEqual(graph.plugin_like, ())
|
|
self.assertEqual(graph.skill_like, ())
|
|
|
|
def test_fields_are_tuples(self) -> None:
|
|
b = (_module("b1", "core/b1.ts"),)
|
|
p = (_module("p1", "plugin/p1.ts"),)
|
|
s = (_module("s1", "skills/s1.ts"),)
|
|
graph = CommandGraph(builtins=b, plugin_like=p, skill_like=s)
|
|
self.assertIsInstance(graph.builtins, tuple)
|
|
self.assertIsInstance(graph.plugin_like, tuple)
|
|
self.assertIsInstance(graph.skill_like, tuple)
|
|
|
|
def test_frozen_dataclass_rejects_mutation(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
with self.assertRaises(AttributeError):
|
|
graph.builtins = () # type: ignore[misc]
|
|
|
|
# -- flattened -------------------------------------------------------------
|
|
|
|
def test_flattened_combines_all_categories(self) -> None:
|
|
b = (_module("b1", "core/b1.ts"),)
|
|
p = (_module("p1", "plugin/p1.ts"),)
|
|
s = (_module("s1", "skills/s1.ts"),)
|
|
graph = CommandGraph(builtins=b, plugin_like=p, skill_like=s)
|
|
self.assertEqual(graph.flattened(), b + p + s)
|
|
|
|
def test_flattened_preserves_order(self) -> None:
|
|
b1 = _module("b1", "core/b1.ts")
|
|
b2 = _module("b2", "core/b2.ts")
|
|
p1 = _module("p1", "plugin/p1.ts")
|
|
s1 = _module("s1", "skills/s1.ts")
|
|
graph = CommandGraph(builtins=(b1, b2), plugin_like=(p1,), skill_like=(s1,))
|
|
self.assertEqual(graph.flattened(), (b1, b2, p1, s1))
|
|
|
|
def test_flattened_of_empty_graph_returns_empty_tuple(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
self.assertEqual(graph.flattened(), ())
|
|
|
|
def test_flattened_length_is_sum_of_categories(self) -> None:
|
|
b = (_module("b1", "core/b1.ts"), _module("b2", "core/b2.ts"))
|
|
p = (_module("p1", "plugin/p1.ts"),)
|
|
s = ()
|
|
graph = CommandGraph(builtins=b, plugin_like=p, skill_like=s)
|
|
self.assertEqual(len(graph.flattened()), 3)
|
|
|
|
# -- as_markdown -----------------------------------------------------------
|
|
|
|
def test_as_markdown_includes_header(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
md = graph.as_markdown()
|
|
self.assertIn("# Command Graph", md)
|
|
|
|
def test_as_markdown_includes_counts(self) -> None:
|
|
b = (_module("b1", "core/b1.ts"), _module("b2", "core/b2.ts"))
|
|
p = (_module("p1", "plugin/p1.ts"),)
|
|
s = (_module("s1", "skills/s1.ts"), _module("s2", "skills/s2.ts"), _module("s3", "skills/s3.ts"))
|
|
graph = CommandGraph(builtins=b, plugin_like=p, skill_like=s)
|
|
md = graph.as_markdown()
|
|
self.assertIn("Builtins: 2", md)
|
|
self.assertIn("Plugin-like commands: 1", md)
|
|
self.assertIn("Skill-like commands: 3", md)
|
|
|
|
def test_as_markdown_empty_counts(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
md = graph.as_markdown()
|
|
self.assertIn("Builtins: 0", md)
|
|
self.assertIn("Plugin-like commands: 0", md)
|
|
self.assertIn("Skill-like commands: 0", md)
|
|
|
|
def test_as_markdown_returns_string(self) -> None:
|
|
graph = CommandGraph(builtins=(), plugin_like=(), skill_like=())
|
|
self.assertIsInstance(graph.as_markdown(), str)
|
|
|
|
|
|
class BuildCommandGraphTests(unittest.TestCase):
|
|
# -- return type -----------------------------------------------------------
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_returns_command_graph(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
mock_get.return_value = ()
|
|
result = build_command_graph()
|
|
self.assertIsInstance(result, CommandGraph)
|
|
|
|
# -- categorization --------------------------------------------------------
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_plugin_source_goes_to_plugin_like(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
p = _module("p1", "plugin/p1.ts")
|
|
mock_get.return_value = (p,)
|
|
graph = build_command_graph()
|
|
self.assertIn(p, graph.plugin_like)
|
|
self.assertNotIn(p, graph.builtins)
|
|
self.assertNotIn(p, graph.skill_like)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_skills_source_goes_to_skill_like(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
s = _module("s1", "skills/s1.ts")
|
|
mock_get.return_value = (s,)
|
|
graph = build_command_graph()
|
|
self.assertIn(s, graph.skill_like)
|
|
self.assertNotIn(s, graph.builtins)
|
|
self.assertNotIn(s, graph.plugin_like)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_plain_source_goes_to_builtins(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
b = _module("b1", "core/b1.ts")
|
|
mock_get.return_value = (b,)
|
|
graph = build_command_graph()
|
|
self.assertIn(b, graph.builtins)
|
|
self.assertNotIn(b, graph.plugin_like)
|
|
self.assertNotIn(b, graph.skill_like)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_case_insensitive_plugin_match(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
p = _module("p1", "Plugin/p1.ts")
|
|
mock_get.return_value = (p,)
|
|
graph = build_command_graph()
|
|
self.assertIn(p, graph.plugin_like)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_case_insensitive_skills_match(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
s = _module("s1", "Skills/s1.ts")
|
|
mock_get.return_value = (s,)
|
|
graph = build_command_graph()
|
|
self.assertIn(s, graph.skill_like)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_mixed_commands_are_sorted_correctly(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
b = _module("b1", "core/b1.ts")
|
|
p = _module("p1", "plugin/p1.ts")
|
|
s = _module("s1", "skills/s1.ts")
|
|
mock_get.return_value = (b, p, s)
|
|
graph = build_command_graph()
|
|
self.assertEqual(graph.builtins, (b,))
|
|
self.assertEqual(graph.plugin_like, (p,))
|
|
self.assertEqual(graph.skill_like, (s,))
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_empty_commands_yields_empty_graph(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
mock_get.return_value = ()
|
|
graph = build_command_graph()
|
|
self.assertEqual(graph.builtins, ())
|
|
self.assertEqual(graph.plugin_like, ())
|
|
self.assertEqual(graph.skill_like, ())
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_all_builtins(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
b1 = _module("b1", "core/b1.ts")
|
|
b2 = _module("b2", "commands/b2.ts")
|
|
mock_get.return_value = (b1, b2)
|
|
graph = build_command_graph()
|
|
self.assertEqual(len(graph.builtins), 2)
|
|
self.assertEqual(graph.plugin_like, ())
|
|
self.assertEqual(graph.skill_like, ())
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_builtins_plugin_skill_are_tuples_of_porting_module(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
b = _module("b1", "core/b1.ts")
|
|
p = _module("p1", "plugin/p1.ts")
|
|
s = _module("s1", "skills/s1.ts")
|
|
mock_get.return_value = (b, p, s)
|
|
graph = build_command_graph()
|
|
for category in (graph.builtins, graph.plugin_like, graph.skill_like):
|
|
self.assertIsInstance(category, tuple)
|
|
for item in category:
|
|
self.assertIsInstance(item, PortingModule)
|
|
|
|
@patch("src.command_graph.get_commands")
|
|
def test_flattened_matches_original_commands(self, mock_get: unittest.mock.MagicMock) -> None:
|
|
modules = (
|
|
_module("b1", "core/b1.ts"),
|
|
_module("p1", "plugin/p1.ts"),
|
|
_module("s1", "skills/s1.ts"),
|
|
)
|
|
mock_get.return_value = modules
|
|
graph = build_command_graph()
|
|
self.assertEqual(set(graph.flattened()), set(modules))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|