def test_simple_cycle(self): a = [0] b = [1] a.append(b) b.append(a) graph = ObjectGraph([a, b]) self.assertCountEqual(graph.references(), [(a, b), (b, a)])
def test_single_edge(self): a = [0] b = [1] a.append(b) graph = ObjectGraph([a, b]) self.assertEqual(len(graph), 2) self.assertEqual(graph.references(), [(a, b)])
def test_sccs(self): a, b, c, d = ["A"], ["B"], ["C"], ["D"] a.append(b) b.append(a) c.append(d) d.append(c) b.append(d) graph = ObjectGraph([a, b, c, d]) sccs = graph.strongly_connected_components() self.assertEqual(len(sccs), 2) self.assertEqual(len(sccs[0]), 2) self.assertEqual(len(sccs[1]), 2) # Identify the two sccs. scc_ab = next(scc for scc in sccs if a in scc) scc_cd = next(scc for scc in sccs if c in scc) self.assertIn(a, scc_ab) self.assertIn(b, scc_ab) self.assertNotIn(c, scc_ab) self.assertNotIn(d, scc_ab) self.assertNotIn(a, scc_cd) self.assertNotIn(b, scc_cd) self.assertIn(c, scc_cd) self.assertIn(d, scc_cd) # Check that they've got the expected edges. self.assertEqual(scc_ab.children(a), [b]) self.assertEqual(scc_ab.children(b), [a]) self.assertEqual(scc_cd.children(c), [d]) self.assertEqual(scc_cd.children(d), [c])
def test_multiple_edges(self): a = [0] b = [1] a.append(b) a.append(b) graph = ObjectGraph([a, b]) self.assertEqual(graph.references(), [(a, b), (a, b)])
def test_long_chain(self): # The original recursive algorithms failed on long chains. objects = [[]] for _ in range(10000): new_object = [] objects[-1].append(new_object) objects.append(new_object) refgraph = ObjectGraph(objects) sccs = refgraph.strongly_connected_components() self.assertEqual(len(sccs), len(objects))
def test_to_dot(self): a = [] b = [] a.append(b) graph = ObjectGraph([a, b]) dot = graph.to_dot() self.assertIn('{} -> {} [label="item[0]"];'.format(id(a), id(b)), dot) self.assertIn('{} [label="list[1]"];'.format(id(a)), dot) self.assertIn('{} [label="list[0]"];'.format(id(b)), dot) self.assertIsInstance(dot, six.text_type)
def test_construction_from_iterator(self): a = [0] b = [1] a.append(b) b.append(a) objects = iter([a, b, a[0], b[0]]) graph = ObjectGraph(objects) self.assertEqual(len(graph), 4) # Check that we get all the edges we expect. self.assertEqual(len(graph.children(a)), 2) self.assertEqual(len(graph.children(b)), 2)
def test_to_json(self): # XXX Needs a better test. For now, just exercise the # to_json method. a = [] b = [] a.append(b) graph = ObjectGraph([a, b]) json_graph = graph.to_json() self.assertIsInstance(json_graph, six.text_type) # Make sure that the result is valid json. json.loads(json_graph)
def test_analyze_simple_cycle(self): original_objects = gc.get_objects() create_cycle() new_objects = gc.get_objects() original_ids = set(map(id, original_objects)) new_objects = [obj for obj in new_objects if id(obj) not in original_ids if obj is not original_objects] refgraph = ObjectGraph(new_objects) sccs = list(refgraph.strongly_connected_components()) self.assertEqual(len(sccs), 1) self.assertEqual(len(sccs[0]), 4)
def test_ancestors(self): a = [] b = [] c = [] d = [] a.append(b) a.append(c) b.append(d) c.append(d) graph = ObjectGraph([a, b, c, d]) self.assertCountEqual(graph.ancestors(a), [a]) self.assertCountEqual(graph.ancestors(b), [b, a]) self.assertCountEqual(graph.ancestors(c), [c, a]) self.assertCountEqual(graph.ancestors(d), [d, b, c, a])
def test_descendants(self): a = [] b = [] c = [] d = [] a.append(b) a.append(c) b.append(d) c.append(d) graph = ObjectGraph([a, b, c, d]) self.assertCountEqual(graph.descendants(a), [a, b, c, d]) self.assertCountEqual(graph.descendants(b), [b, d]) self.assertCountEqual(graph.descendants(c), [c, d]) self.assertCountEqual(graph.descendants(d), [d])
def test_parents(self): a = [] b = [] c = [] d = [] a.append(b) a.append(c) b.append(d) c.append(d) graph = ObjectGraph([a, b, c, d]) self.assertCountEqual(graph.parents(a), []) self.assertCountEqual(graph.parents(b), [a]) self.assertCountEqual(graph.parents(c), [a]) self.assertCountEqual(graph.parents(d), [b, c])
def test_children(self): a = [] b = [] c = [] d = [] a.append(b) a.append(c) b.append(d) c.append(d) graph = ObjectGraph([a, b, c, d]) self.assertCountEqual(graph.children(a), [b, c]) self.assertCountEqual(graph.children(b), [d]) self.assertCountEqual(graph.children(c), [d]) self.assertCountEqual(graph.children(d), [])
def objects_reachable_from(obj): """ Return graph of objects reachable from *obj* via ``gc.get_referrers``. Returns an :class:`~refcycle.object_graph.ObjectGraph` object holding all objects reachable from the given one by following the output of ``gc.get_referrers``. Note that unlike the :func:`~refcycle.creators.snapshot` function, the output graph may include non-gc-tracked objects. """ # Depth-first search. found = ObjectGraph.vertex_set() to_process = [obj] while to_process: obj = to_process.pop() found.add(obj) for referent in gc.get_referents(obj): if referent not in found: to_process.append(referent) return ObjectGraph(found)
def test_source_components(self): # Single source consisting of two objects. a, b, c, d = ["A"], ["B"], ["C"], ["D"] a.append(b) b.append(a) c.append(d) d.append(c) b.append(d) graph = ObjectGraph([a, b, c, d]) sources = graph.source_components() self.assertEqual(len(sources), 1) source = sources[0] self.assertIn(a, source) self.assertIn(b, source) self.assertNotIn(c, source) self.assertNotIn(d, source) # Single source consisting of one object. a, b, c, d = ["A"], ["B"], ["C"], ["D"] a.append(b) b.append(d) c.append(a) graph = ObjectGraph([a, b, c, d]) sources = graph.source_components() self.assertEqual(len(sources), 1) source = sources[0] self.assertNotIn(a, source) self.assertNotIn(b, source) self.assertIn(c, source) self.assertNotIn(d, source) # Multiple sources. a, b, c, d, e, f = ["A"], ["B"], ["C"], ["D"], ["E"], ["F"] a.append(b) b.append(d) c.append(a) e.append(d) graph = ObjectGraph([a, b, c, d, e, f]) sources = graph.source_components() self.assertEqual(len(sources), 3)
def test_self_reference(self): a = [0] a.append(a) graph = ObjectGraph([a]) self.assertEqual(graph.references(), [(a, a)])