def setUp(self): self.cgraph = CGraph('foo', None, suiterc['visualization']) edges = [('foo.1', 'bar.1', False, False, False), ('foo.1', 'baz.1', False, False, False), ('bar.1', 'qux.1', False, False, False), ('baz.1', 'qux.1', False, False, False), ('foo.2', 'bar.2', False, False, False), ('foo.2', 'baz.2', False, False, False), ('bar.2', 'qux.2', False, False, False), ('baz.2', 'qux.2', False, False, False), ('foo.3', 'bar.3', False, False, False), ('foo.3', 'baz.3', False, False, False), ('bar.3', 'qux.3', False, False, False), ('baz.3', 'qux.3', False, False, False)] self.cgraph.add_edges(edges)
class TestGraphParser(unittest.TestCase): """Unit tests for the graphing module.""" def setUp(self): self.cgraph = CGraph('foo', None, suiterc['visualization']) edges = [('foo.1', 'bar.1', False, False, False), ('foo.1', 'baz.1', False, False, False), ('bar.1', 'qux.1', False, False, False), ('baz.1', 'qux.1', False, False, False), ('foo.2', 'bar.2', False, False, False), ('foo.2', 'baz.2', False, False, False), ('bar.2', 'qux.2', False, False, False), ('baz.2', 'qux.2', False, False, False), ('foo.3', 'bar.3', False, False, False), ('foo.3', 'baz.3', False, False, False), ('bar.3', 'qux.3', False, False, False), ('baz.3', 'qux.3', False, False, False)] self.cgraph.add_edges(edges) def test_gtk_rgb_to_hex(self): self.assertEqual(gtk_rgb_to_hex(fake_gtk_color()), '#ffffff') def test_node_attr_by_taskname(self): self.assertEqual(self.cgraph.node_attr_by_taskname('foo.1'), ['style=filled', 'fillcolor=yellow']) def test_style_node(self): node_str = 'foo.1' self.cgraph.style_node(node_str) node = self.cgraph.get_node(node_str) self.assertEqual(node.attr.items(), [(u'URL', u'foo.1'), (u'fillcolor', u'yellow'), (u'label', u'foo\\n1'), (u'penwidth', u'2')]) def test_set_def_style(self): fgcolor = 'red' bgcolor = 'blue' def_node_attr = {} def_node_attr['style'] = 'filled' self.cgraph.set_def_style(fgcolor, bgcolor, def_node_attr) self.assertEqual(self.cgraph.graph_attr['bgcolor'], '#ffffff00') for attr in ['color', 'fontcolor']: self.assertEqual(self.cgraph.graph_attr[attr], fgcolor) self.assertEqual(self.cgraph.edge_attr['color'], fgcolor) self.assertEqual(self.cgraph.node_attr['fontcolor'], fgcolor) def_node_attr['style'] = 'unfilled' self.cgraph.set_def_style(fgcolor, bgcolor, def_node_attr) self.assertEqual(self.cgraph.node_attr['fontcolor'], fgcolor)
def get_graph(self, group_nodes=None, ungroup_nodes=None, ungroup_recursive=False, ungroup_all=False, group_all=False): if not self.suiterc: return family_nodes = self.suiterc.get_first_parent_descendants() # Note this is used by "cylc graph" but not gcylc. # self.start_ and self.stop_point_string come from CLI. graph = CGraph.get_graph( self.suiterc, group_nodes=group_nodes, ungroup_nodes=ungroup_nodes, ungroup_recursive=ungroup_recursive, group_all=group_all, ungroup_all=ungroup_all, ignore_suicide=self.ignore_suicide, subgraphs_on=self.subgraphs_on) graph.graph_attr['rankdir'] = self.orientation # Style nodes. cache = {} # For caching is_on_sequence() calls. for node in graph.iternodes(): name, point = TaskID.split(node.get_name()) if name in family_nodes: # Style family nodes. node.attr['shape'] = 'doubleoctagon' # Detecting ghost families would involve analysing triggers # in the suite's graphing. elif self.is_ghost_task(name, point, cache=cache): # Style ghost nodes. style_ghost_node(node) self.graph = graph self.filter_graph() self.set_dotcode(graph.string())
def get_graph(self, group_nodes=None, ungroup_nodes=None, ungroup_recursive=False, ungroup_all=False, group_all=False): if not self.suiterc: return family_nodes = self.suiterc.get_first_parent_descendants() # Note this is used by "cylc graph" but not gcylc. # self.start_ and self.stop_point_string come from CLI. bg_color = gtk_rgb_to_hex( getattr(self.style, 'bg', None)[gtk.STATE_NORMAL]) fg_color = gtk_rgb_to_hex( getattr(self.style, 'fg', None)[gtk.STATE_NORMAL]) graph = CGraph.get_graph(self.suiterc, group_nodes=group_nodes, ungroup_nodes=ungroup_nodes, ungroup_recursive=ungroup_recursive, group_all=group_all, ungroup_all=ungroup_all, ignore_suicide=self.ignore_suicide, subgraphs_on=self.subgraphs_on, bgcolor=bg_color, fgcolor=fg_color) graph.graph_attr['rankdir'] = self.orientation # Style nodes. cache = {} # For caching is_on_sequence() calls. fg_ghost = "%s%s" % (fg_color, GHOST_TRANSP_HEX) for node in graph.iternodes(): name, point = TaskID.split(node.get_name()) if name.startswith('@'): # Style action trigger nodes. node.attr['shape'] = 'none' elif name in family_nodes: # Style family nodes. node.attr['shape'] = 'doubleoctagon' # Detecting ghost families would involve analysing triggers # in the suite's graphing. elif self.is_off_sequence(name, point, cache=cache): node.attr['style'] = 'dotted' node.attr['color'] = fg_ghost node.attr['fontcolor'] = fg_ghost self.graph = graph self.filter_graph() self.set_dotcode(graph.string())