def test_render__with_style(self): master_graph = MasterGraph.from_tuple_list([("a", "b"), ("b", "c")]) graph = Graph(master_graph) graph.style( node("b"), color=Color.Blue, fontcolor=Color.Red, penwidth=PenWidth.Bold ) renderer = GraphRenderer(graph=graph) g = Digraph() default_node_style = NodeStyle().to_dict() node_style = NodeStyle().to_dict() node_style.update( { "color": "blue", "fontcolor": "red", "penwidth": PenWidth.to_size(PenWidth.Bold), } ) g.node("a", **default_node_style) g.node("b", **node_style) g.node("c", **default_node_style) edge_style = EdgeStyle().to_dict() edge_style.update( { "color": "blue", "fontcolor": "red", "penwidth": PenWidth.to_size(PenWidth.Bold), } ) g.edge("a", "b", **edge_style) g.edge("b", "c", **edge_style) assert str(renderer.render()) == str(g)
def test_focus__node_inside_a_package(self): g = Graph() g.add_edge(edge("A", "B")) g.add_cluster(cluster("pkg", {"A"})) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A"], "clusters": {} } }, } g.focus_nodes(node("A")) assert g.to_dict() == { "nodes": ["A"], "edges": [], "clusters": { "pkg": { "nodes": ["A"], "clusters": {} } }, }
def test_render__with_hidden_node(self): # +---+ +---+ +---+ # | |--->| b |--->| | # | | +---+ | | # | a | | d | # | | +---+ | | # | |--->| c |--->| | # +---+ +---+ +---+ master_graph = MasterGraph.from_tuple_list( [("a", "b"), ("a", "c"), ("b", "d"), ("c", "d")] ) graph = Graph(master_graph) renderer = GraphRenderer(graph=graph) graph.hide_node(node("b")) g = Digraph() default_node_style = NodeStyle().to_dict() hidden_node_style = NodeStyle(invisible=True).to_dict() g.node("a", **default_node_style) g.node("b", **hidden_node_style) g.node("c", **default_node_style) g.node("d", **default_node_style) default_edge_style = EdgeStyle().to_dict() hidden_edge_style = EdgeStyle(invisible=True).to_dict() g.edge("a", "b", **hidden_edge_style) g.edge("a", "c", **default_edge_style) g.edge("b", "d", **hidden_edge_style) g.edge("c", "d", **default_edge_style) assert str(renderer.render()) == str(g)
def test_remove_and_dig(self): """ エッジの生えていないクラスタ内ノードが発生したとき、エラーにならずそのノードがGraphのnodesに追加されること """ master_graph = MasterGraph.from_tuple_list([ ("tests.fixtures", "jig.visualizer"), ("tests.visualizer", "jig.visualizer"), ]) g = Graph(master_graph=master_graph) assert g.to_dict() == { "nodes": ["jig", "tests"], "edges": [("tests", "jig")], "clusters": {}, } g.remove_node(node("jig")) assert g.to_dict() == { "nodes": ["tests"], "edges": [], "clusters": {}, } g.dig(node("tests")) assert g.to_dict() == { "nodes": ["tests.fixtures", "tests.visualizer"], "edges": [], "clusters": { "tests": { "nodes": ["tests.fixtures", "tests.visualizer"], "clusters": {}, } }, }
def sample(cls) -> "GraphController": master_graph = MasterGraph(edges=ModuleEdgeCollection([ ModuleEdge.from_str("A.A", "B.B"), ModuleEdge.from_str("X.A", "Y.B") ])) g = Graph(master_graph=master_graph) g.add_edge(ModuleEdge.from_str("A", "B")) g.add_edge(ModuleEdge.from_str("X", "Y")) return cls(g)
def test_remove_cluster__child_cluster(self): # クラスタ内クラスタの削除 master_graph = MasterGraph.from_tuple_list([ ("jig.collector.application", "jig.collector.domain.source_code"), ("jig.collector.application", "jig.collector.domain.source_file"), ( "jig.collector.domain.source_code", "jig.collector.domain.source_file", ), ("jig.cli.main", "jig.collector.application"), ]) g = Graph(master_graph=master_graph) g.dig(node("jig")) g.dig(node("jig.collector")) assert g.to_dict() == { "nodes": ["jig.cli", "jig.collector.application", "jig.collector.domain"], "edges": [ ("jig.cli", "jig.collector.application"), ("jig.collector.application", "jig.collector.domain"), ], "clusters": { "jig": { "clusters": { "jig.collector": { "nodes": [ "jig.collector.application", "jig.collector.domain", ], "clusters": {}, } }, "nodes": ["jig.cli"], }, }, } g.remove_cluster(path("jig.collector")) assert g.to_dict() == { "nodes": ["jig.cli"], "edges": [], "clusters": { "jig": { "clusters": {}, "nodes": ["jig.cli"] } }, }
def test_add_edge(self): g = Graph() g.add_edge(edge("A", "B")) expected = {"nodes": ["A", "B"], "edges": [("A", "B")], "clusters": {}} assert g.to_dict() == expected g.add_edge(edge("A", "B")) assert g.to_dict() == expected
def test_focus_nodes_and_clusters(self): g = Graph() g.add_edge(edge("A", "B")) g.add_edge(edge("C", "D")) cluster_a = cluster("pkg_a", {"A"}) cluster_b = cluster("pkg_b", {"B"}) cluster_a.add_cluster(cluster_b) g.add_cluster(cluster_a) assert g.to_dict() == { "nodes": ["A", "B", "C", "D"], "edges": [("A", "B"), ("C", "D")], "clusters": { "pkg_a": { "clusters": { "pkg_b": { "clusters": {}, "nodes": ["B"] } }, "nodes": ["A"], } }, } g.focus_nodes_and_clusters(node("pkg_b"), node("C")) assert g.to_dict() == { "nodes": ["B", "C"], "edges": [], "clusters": { "pkg_a": { "clusters": { "pkg_b": { "clusters": {}, "nodes": ["B"] } }, "nodes": [], } }, }
def test_find_node_owner(self): g = Graph() g.add_node(node("A")) g.add_node(node("B")) child_cluster = cluster("pkg", {"B"}) g.add_cluster(child_cluster) assert g.find_node_owner(node("foo")) is None assert g.find_node_owner(node("pkg")) is None assert g.find_node_owner(node("A")) is g assert g.find_node_owner(node("B")) is child_cluster
def test_remove_node(self): g = Graph() g.add_edge(edge("A", "B")) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": {}, } g.remove_node(node("A")) assert g.to_dict() == {"nodes": ["B"], "edges": [], "clusters": {}}
def test_find_cluster(self): g = Graph() g.add_node(node("A")) g.add_node(node("B")) cluster_a = cluster("pkg_A", {"A"}) cluster_b = cluster("pkg_B", {"B"}) cluster_a.add_cluster(cluster_b) g.add_cluster(cluster_a) assert g.find_cluster(path("x")) is None assert g.find_cluster(path("pkg_A")) is cluster_a assert g.find_cluster(path("pkg_B")) is cluster_b
def test_predecessors(self): g = Graph() g.add_edge(edge("A", "B")) assert g.predecessors(node("A")) == [] assert g.predecessors(node("B")) == [node("A")] assert g.predecessors(node("C")) == []
def test_render__with_autohighlight(self): # +---+ +---+ +---+ +---+ # | | | |--->| | | | # | a |--->| b | | c |--->| d | # | | | |<---| | | | # +---+ +---+ +---+ +---+ master_graph = MasterGraph.from_tuple_list( [("a", "b"), ("b", "c"), ("c", "b"), ("c", "d")] ) graph = Graph(master_graph) renderer = GraphRenderer(graph=graph) graph.auto_highlight() g = Digraph() default_node_style = NodeStyle().to_dict() entry_point_node_style = NodeStyle( color=Color.Teal, fontcolor=Color.White, filled=True ).to_dict() fundamental_node_style = NodeStyle( color=Color.Purple, fontcolor=Color.White, filled=True ).to_dict() g.node("a", **entry_point_node_style) g.node("b", **default_node_style) g.node("c", **default_node_style) g.node("d", **fundamental_node_style) default_edge_style = EdgeStyle().to_dict() warning_edge_style = EdgeStyle( color=Color.Red, penwidth=PenWidth.Bold ).to_dict() g.edge("a", "b", **default_edge_style) g.edge("b", "c", **warning_edge_style) g.edge("c", "b", **warning_edge_style) g.edge("c", "d", **default_edge_style) assert str(renderer.render()) == str(g)
def test_remove_node_from_cluster(self): g = Graph() g.add_edge(edge("A", "B")) g.add_cluster(cluster("pkg", {"A"})) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A"], "clusters": {} } }, } g.remove_node(node("A")) assert g.to_dict() == { "nodes": ["B"], "edges": [], "clusters": {}, }
def analyze_module_dependency(cls, project_root_path: str) -> GraphController: source_codes = _collect_source_codes( project_root_path=project_root_path) collection = ImportDependencyCollection.build_from_source_code_collection( source_codes) dependencies = collection.build_module_dependencies() dependency_tuples = [] for dependency in dependencies: dependency_tuples.append( (str(dependency.src), str(dependency.dest))) master_graph = MasterGraph.from_tuple_list(dependency_tuples) graph = Graph(master_graph=master_graph) return GraphController(graph=graph)
def test_list_all_modules(self): g = Graph() g.add_edge(edge("A", "B")) cluster_a = cluster("pkg", {"A"}) cluster_b = cluster("pkg.xxx", {"B"}) cluster_a.add_cluster(cluster_b) g.add_cluster(cluster_a) assert g.list_all_modules() == [ path("A"), path("B"), path("pkg"), path("pkg.xxx"), ]
def test_list_all_nodes(self): g = Graph() g.add_edge(edge("A", "B")) g.add_edge(edge("A", "C")) cluster_a = cluster("pkg", {"A"}) cluster_b = cluster("pkg.xxx", {"B"}) cluster_a.add_cluster(cluster_b) g.add_cluster(cluster_a) assert g.list_all_nodes() == [ node("A"), node("B"), node("C"), ]
def test_render__reset_style(self): master_graph = MasterGraph.from_tuple_list([("a", "b"), ("b", "c")]) graph = Graph(master_graph) graph.style( node("b"), color=Color.Blue, fontcolor=Color.Red, penwidth=PenWidth.Bold ) graph.reset_style() renderer = GraphRenderer(graph=graph) g = Digraph() default_node_style = NodeStyle().to_dict() g.node("a", **default_node_style) g.node("b", **default_node_style) g.node("c", **default_node_style) default_edge_style = EdgeStyle().to_dict() g.edge("a", "b", **default_edge_style) g.edge("b", "c", **default_edge_style) assert str(renderer.render()) == str(g)
def test_render(self): cluster = Cluster(module_path=path("jig"), children={node("jig.analyzer")}) sub_cluster = Cluster( module_path=path("jig.collector"), children={node("jig.collector.application"), node("jig.collector.domain")}, ) cluster.add_cluster(sub_cluster) graph = Graph() graph.add_edge(edge("jig.analyzer", "jig.collector")) graph.add_cluster(cluster) renderer = GraphRenderer(graph=graph) g = Digraph() node_style = NodeStyle().to_dict() g.node("jig.analyzer", **node_style) g.node("jig.collector", **node_style) edge_style = EdgeStyle().to_dict() g.edge("jig.analyzer", "jig.collector", **edge_style) child = Digraph(name="cluster_jig") child.attr(label="jig") child.node("jig.analyzer") grandchild = Digraph(name="cluster_jig.collector") grandchild.attr(label="jig.collector") grandchild.node("jig.collector.application") grandchild.node("jig.collector.domain") child.subgraph(grandchild) g.subgraph(child) assert str(renderer.render()) == str(g)
def test_is_removed_node(self): # クラスタ内クラスタの削除 master_graph = MasterGraph.from_tuple_list([ ("jig.collector.application", "jig.collector.domain.source_code"), ("jig.collector.application", "jig.collector.domain.source_file"), ( "jig.collector.domain.source_code", "jig.collector.domain.source_file", ), ("jig.cli.main", "jig.collector.application"), ]) g = Graph(master_graph=master_graph) g.dig(node("jig")) g.dig(node("jig.collector")) assert g.to_dict() == { "nodes": ["jig.cli", "jig.collector.application", "jig.collector.domain"], "edges": [ ("jig.cli", "jig.collector.application"), ("jig.collector.application", "jig.collector.domain"), ], "clusters": { "jig": { "clusters": { "jig.collector": { "nodes": [ "jig.collector.application", "jig.collector.domain", ], "clusters": {}, } }, "nodes": ["jig.cli"], }, }, } assert g.is_removed_node(node("the.name.is.not.in.the.graph")) is False assert g.is_removed_node(node("jig")) is False assert g.is_removed_node(node("jig.cli")) is False assert g.is_removed_node(node("jig.collector")) is False assert g.is_removed_node(node("jig.collector.application")) is False assert g.is_removed_node(node("jig.collector.domain")) is False g.remove_node(node("jig.cli")) assert g.is_removed_node(node("jig.cli")) is True assert g.is_removed_node(node("jig")) is False g.remove_node(node("jig.collector.application")) assert g.is_removed_node(node("jig.collector.application")) is True assert g.is_removed_node(node("jig.collector")) is False g.remove_node(node("jig.collector.domain")) assert g.is_removed_node(node("jig.collector.domain")) is True assert g.is_removed_node(node("jig.collector")) is True assert g.is_removed_node(node("jig")) is True
def test_add_cluster(self): g = Graph() g.add_edge(edge("A", "B")) g.add_cluster(cluster("pkg", {"A", "B"})) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A", "B"], "clusters": {} } }, } g.clusters[path("pkg")].add_cluster(cluster("pkg.child", {"C"})) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A", "B"], "clusters": { "pkg.child": { "clusters": {}, "nodes": ["C"] } }, } }, } # 親グラフが持っていないノードを含むクラスタが追加されたら、 # 親グラフに含まれないノードを親グラフのノード管理に含める g.add_cluster(cluster("pkg_x", {"X"})) assert g.to_dict() == { "nodes": ["A", "B", "X"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A", "B"], "clusters": { "pkg.child": { "clusters": {}, "nodes": ["C"] } }, }, "pkg_x": { "nodes": ["X"], "clusters": {} }, }, }
def test_remove_and_dig_inside_cluster(self): """ エッジの生えていないノードがネストされたクラスタ内で発生したとき、そのノードがGraphのnodesに追加されること """ master_graph = MasterGraph.from_tuple_list([("tests.fixtures.download", "jig.visualizer")]) g = Graph(master_graph=master_graph) assert g.to_dict() == { "nodes": ["jig", "tests"], "edges": [("tests", "jig")], "clusters": {}, } g.dig(node("tests")) assert g.to_dict() == { "nodes": ["jig", "tests.fixtures"], "edges": [("tests.fixtures", "jig")], "clusters": { "tests": { "nodes": ["tests.fixtures"], "clusters": {} } }, } g.remove_node(node("jig")) assert g.to_dict() == { "nodes": ["tests.fixtures"], "edges": [], "clusters": { "tests": { "nodes": ["tests.fixtures"], "clusters": {} } }, } g.dig(node("tests.fixtures")) assert g.to_dict() == { "nodes": ["tests.fixtures.download"], "edges": [], "clusters": { "tests": { "nodes": [], "clusters": { "tests.fixtures": { "nodes": ["tests.fixtures.download"], "clusters": {}, } }, } }, }
def test_remove_cluster(self): # Graph所有のクラスタ削除 g = Graph() g.add_edge(edge("A", "B")) g.add_cluster(cluster("pkg", {"A"})) assert g.to_dict() == { "nodes": ["A", "B"], "edges": [("A", "B")], "clusters": { "pkg": { "nodes": ["A"], "clusters": {} } }, } g.remove_cluster(path("pkg")) assert g.to_dict() == { "nodes": ["B"], "edges": [], "clusters": {}, } # 冪等なこと g.remove_cluster(path("pkg")) assert g.to_dict() == { "nodes": ["B"], "edges": [], "clusters": {}, }
def test_dig_node_not_found(self): g = Graph() g.add_node(node("jig")) with pytest.raises(ValueError): g.dig(node("foo"))
def test_restore(self): # クラスタ内クラスタの削除 master_graph = MasterGraph.from_tuple_list([ ("jig.collector.application", "jig.collector.domain.source_code"), ("jig.collector.application", "jig.collector.domain.source_file"), ( "jig.collector.domain.source_code", "jig.collector.domain.source_file", ), ("jig.cli.main", "jig.collector.application"), ]) g = Graph(master_graph=master_graph) g.dig(node("jig")) g.dig(node("jig.collector")) assert g.to_dict() == { "nodes": ["jig.cli", "jig.collector.application", "jig.collector.domain"], "edges": [ ("jig.cli", "jig.collector.application"), ("jig.collector.application", "jig.collector.domain"), ], "clusters": { "jig": { "clusters": { "jig.collector": { "nodes": [ "jig.collector.application", "jig.collector.domain", ], "clusters": {}, } }, "nodes": ["jig.cli"], }, }, } # 存在しないノード with pytest.raises(InvalidRestoreTargetError): g.restore_node(node("invalid.node.name")) # 削除されていないノード with pytest.raises(InvalidRestoreTargetError): g.restore_node(node("jig.cli")) before_dict = g.to_dict() # 接続先があるノードの復元 g.remove_node(node("jig.cli")) g.restore_node(node("jig.cli")) assert g.to_dict() == before_dict # 接続元があるノードの復元 g.remove_node(node("jig.collector.domain")) g.restore_node(node("jig.collector.domain")) assert g.to_dict() == before_dict
def test_dig_complex(self): master_graph = MasterGraph.from_tuple_list([ ("jig.cli", "jig.analyzer"), ("jig.cli", "jig.visualizer.application"), ("jig.visualizer.application", "jig.analyzer"), ("jig.visualizer.application", "jig.visualizer.domain.edge"), ("jig.visualizer.application", "jig.visualizer.domain.node"), ("jig.visualizer.domain.edge", "jig.visualizer.domain.node"), ]) g = Graph(master_graph=master_graph) assert g.to_dict() == { "nodes": ["jig"], "edges": [], "clusters": {}, } g.dig(node("jig")) assert g.to_dict() == { "nodes": ["jig.analyzer", "jig.cli", "jig.visualizer"], "edges": [ ("jig.cli", "jig.analyzer"), ("jig.cli", "jig.visualizer"), ("jig.visualizer", "jig.analyzer"), ], "clusters": { "jig": { "nodes": ["jig.analyzer", "jig.cli", "jig.visualizer"], "clusters": {}, } }, } g.dig(node("jig.visualizer")) assert g.to_dict() == { "nodes": [ "jig.analyzer", "jig.cli", "jig.visualizer.application", "jig.visualizer.domain", ], "edges": [ ("jig.cli", "jig.analyzer"), ("jig.cli", "jig.visualizer.application"), ("jig.visualizer.application", "jig.analyzer"), ("jig.visualizer.application", "jig.visualizer.domain"), ], "clusters": { "jig": { "nodes": ["jig.analyzer", "jig.cli"], "clusters": { "jig.visualizer": { "nodes": [ "jig.visualizer.application", "jig.visualizer.domain", ], "clusters": {}, }, }, }, }, } g.dig(node("jig.visualizer.domain")) assert g.to_dict() == { "nodes": [ "jig.analyzer", "jig.cli", "jig.visualizer.application", "jig.visualizer.domain.edge", "jig.visualizer.domain.node", ], "edges": [ ("jig.cli", "jig.analyzer"), ("jig.cli", "jig.visualizer.application"), ("jig.visualizer.application", "jig.analyzer"), ("jig.visualizer.application", "jig.visualizer.domain.edge"), ("jig.visualizer.application", "jig.visualizer.domain.node"), ("jig.visualizer.domain.edge", "jig.visualizer.domain.node"), ], "clusters": { "jig": { "nodes": ["jig.analyzer", "jig.cli"], "clusters": { "jig.visualizer": { "nodes": ["jig.visualizer.application"], "clusters": { "jig.visualizer.domain": { "nodes": [ "jig.visualizer.domain.edge", "jig.visualizer.domain.node", ], "clusters": {}, }, }, }, }, }, }, }
def test_focus__node_not_found(self): g = Graph() g.add_edge(edge("A", "B")) with pytest.raises(Exception): g.focus_nodes(node("C"))