summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/portage/tests/util/test_digraph.py201
-rw-r--r--pym/portage/util/digraph.py34
2 files changed, 222 insertions, 13 deletions
diff --git a/pym/portage/tests/util/test_digraph.py b/pym/portage/tests/util/test_digraph.py
new file mode 100644
index 000000000..9b95a596f
--- /dev/null
+++ b/pym/portage/tests/util/test_digraph.py
@@ -0,0 +1,201 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.util.digraph import digraph
+#~ from portage.util import noiselimit
+import portage.util
+
+class DigraphTest(TestCase):
+
+ def testBackwardCompatibility(self):
+ g = digraph()
+ f = g.copy()
+ g.addnode("A", None)
+ self.assertEqual("A" in g, True)
+ self.assertEqual(g.empty(), False)
+ self.assertEqual(g.allnodes(), ["A"])
+ self.assertEqual(g.allzeros(), ["A"])
+ self.assertEqual(g.hasnode("A"), True)
+
+ def testDigraphEmptyGraph(self):
+ g = digraph()
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(x.is_empty(), True)
+ self.assertEqual(x.contains("A"), False)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "A")
+ x.delnode("A")
+ self.assertEqual(list(x), [])
+ self.assertEqual(x.get("A"), None)
+ self.assertEqual(x.get("A", "default"), "default")
+ self.assertEqual(x.all_nodes(), [])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertRaises(KeyError, x.child_nodes, "A")
+ self.assertRaises(KeyError, x.parent_nodes, "A")
+ self.assertEqual(x.hasallzeros(), True)
+ self.assertRaises(KeyError, list, x.bfs("A"))
+ self.assertRaises(KeyError, x.shortest_path, "A", "B")
+ self.assertRaises(KeyError, x.remove_edge, "A", "B")
+ self.assertEqual(x.get_cycles(), [])
+ x.difference_update("A")
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphCircle(self):
+ g = digraph()
+ g.add("A", "B", -1)
+ g.add("B", "C", 0)
+ g.add("C", "D", 1)
+ g.add("D", "A", 2)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(x.is_empty(), False)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(list(x), ["A", "B", "C", "D"])
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(x.all_nodes(), ["A", "B", "C", "D"])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertEqual(x.child_nodes("A"), ["D"])
+ self.assertEqual(x.child_nodes("A", ignore_priority=2), [])
+ self.assertEqual(x.parent_nodes("A"), ["B"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=-2), ["B"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=-1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "D"), ("D", "C"), ("C", "B")])
+ self.assertEqual(x.shortest_path("A", "D"), ["A", "D"])
+ self.assertEqual(x.shortest_path("D", "A"), ["D", "C", "B", "A"])
+ self.assertEqual(x.shortest_path("A", "D", ignore_priority=2), None)
+ self.assertEqual(x.shortest_path("D", "A", ignore_priority=-2), ["D", "C", "B", "A"])
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set([("D", "C", "B", "A"), ("C", "B", "A", "D"), ("B", "A", "D", "C"), \
+ ("A", "D", "C", "B")]))
+ x.remove_edge("A", "B")
+ self.assertEqual(x.get_cycles(), [])
+ x.difference_update(["D"])
+ self.assertEqual(x.all_nodes(), ["A", "B", "C"])
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphTree(self):
+ g = digraph()
+ g.add("B", "A", -1)
+ g.add("C", "A", 0)
+ g.add("D", "C", 1)
+ g.add("E", "C", 2)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(x.is_empty(), False)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), "B")
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(set(x), set(["A", "B", "C", "D", "E"]))
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "C", "D", "E"]))
+ self.assertEqual(set(x.leaf_nodes()), set(["B", "D", "E"]))
+ self.assertEqual(set(x.leaf_nodes(ignore_priority=0)), set(["A", "B", "D", "E"]))
+ self.assertEqual(x.root_nodes(), ["A"])
+ self.assertEqual(set(x.root_nodes(ignore_priority=0)), set(["A", "B", "C"]))
+ self.assertEqual(set(x.child_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.child_nodes("A", ignore_priority=2), [])
+ self.assertEqual(x.parent_nodes("B"), ["A"])
+ self.assertEqual(x.parent_nodes("B", ignore_priority=-2), ["A"])
+ self.assertEqual(x.parent_nodes("B", ignore_priority=-1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "C"), ("A", "B"), ("C", "E"), ("C", "D")])
+ self.assertEqual(x.shortest_path("A", "D"), ["A", "C", "D"])
+ self.assertEqual(x.shortest_path("D", "A"), None)
+ self.assertEqual(x.shortest_path("A", "D", ignore_priority=2), None)
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set())
+ x.remove("D")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "C", "E"]))
+ x.remove("C")
+ self.assertEqual(set(x.all_nodes()), set(["A", "B", "E"]))
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+ self.assertRaises(KeyError, x.remove_edge, "A", "E")
+
+ def testDigraphCompleteGraph(self):
+ g = digraph()
+ g.add("A", "B", -1)
+ g.add("B", "A", 1)
+ g.add("A", "C", 1)
+ g.add("C", "A", -1)
+ g.add("C", "B", 1)
+ g.add("B", "C", 1)
+
+ f = g.clone()
+ for x in g, f:
+ self.assertEqual(x.is_empty(), False)
+ self.assertEqual(x.contains("A"), True)
+ self.assertEqual(x.firstzero(), None)
+ self.assertRaises(KeyError, x.remove, "Z")
+ x.delnode("Z")
+ self.assertEqual(list(x), ["A", "B", "C"])
+ self.assertEqual(x.get("A"), "A")
+ self.assertEqual(x.get("A", "default"), "A")
+ self.assertEqual(x.all_nodes(), ["A", "B", "C"])
+ self.assertEqual(x.leaf_nodes(), [])
+ self.assertEqual(x.root_nodes(), [])
+ self.assertEqual(set(x.child_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.child_nodes("A", ignore_priority=0), ["B"])
+ self.assertEqual(set(x.parent_nodes("A")), set(["B", "C"]))
+ self.assertEqual(x.parent_nodes("A", ignore_priority=0), ["C"])
+ self.assertEqual(x.parent_nodes("A", ignore_priority=1), [])
+ self.assertEqual(x.hasallzeros(), False)
+ self.assertEqual(list(x.bfs("A")), [(None, "A"), ("A", "C"), ("A", "B")])
+ self.assertEqual(x.shortest_path("A", "C"), ["A", "C"])
+ self.assertEqual(x.shortest_path("C", "A"), ["C", "A"])
+ self.assertEqual(x.shortest_path("A", "C", ignore_priority=0), ["A", "B", "C"])
+ self.assertEqual(x.shortest_path("C", "A", ignore_priority=0), ["C", "A"])
+ cycles = set(tuple(y) for y in x.get_cycles())
+ self.assertEqual(cycles, set([("C", "A"), ("A", "B"), ("A", "C")]))
+ x.remove_edge("A", "B")
+ self.assertEqual(x.get_cycles(), [["C", "A"], ["A", "C"], ["C", "B"]])
+ x.difference_update(["C"])
+ self.assertEqual(x.all_nodes(), ["A", "B"])
+ portage.util.noiselimit = -2
+ x.debug_print()
+ portage.util.noiselimit = 0
+
+ def testDigraphIgnorePriority(self):
+
+ def always_true(dummy):
+ return True
+
+ def always_false(dummy):
+ return False
+
+ g = digraph()
+ g.add("A", "B")
+
+ self.assertEqual(g.parent_nodes("A"), ["B"])
+ self.assertEqual(g.parent_nodes("A", ignore_priority=always_false), ["B"])
+ self.assertEqual(g.parent_nodes("A", ignore_priority=always_true), [])
+
+ self.assertEqual(g.child_nodes("B"), ["A"])
+ self.assertEqual(g.child_nodes("B", ignore_priority=always_false), ["A"])
+ self.assertEqual(g.child_nodes("B", ignore_priority=always_true), [])
+
+ self.assertEqual(g.leaf_nodes(), ["A"])
+ self.assertEqual(g.leaf_nodes(ignore_priority=always_false), ["A"])
+ self.assertEqual(g.leaf_nodes(ignore_priority=always_true), ["A", "B"])
+
+ self.assertEqual(g.root_nodes(), ["B"])
+ self.assertEqual(g.root_nodes(ignore_priority=always_false), ["B"])
+ self.assertEqual(g.root_nodes(ignore_priority=always_true), ["A", "B"])
diff --git a/pym/portage/util/digraph.py b/pym/portage/util/digraph.py
index 9852bf859..97f9c99b2 100644
--- a/pym/portage/util/digraph.py
+++ b/pym/portage/util/digraph.py
@@ -276,21 +276,29 @@ class digraph(object):
output(" %s (%s)\n" % (child, priorities[-1],))
def bfs(self, start, ignore_priority=None):
- queue, enqueued = deque([(None, start)]), set([start])
- while queue:
- parent, n = queue.popleft()
- yield parent, n
- new = set(self.child_nodes(n, ignore_priority)) - enqueued
- enqueued |= new
- queue.extend([(n, child) for child in new])
+ if start not in self:
+ raise KeyError(start)
+
+ queue, enqueued = deque([(None, start)]), set([start])
+ while queue:
+ parent, n = queue.popleft()
+ yield parent, n
+ new = set(self.child_nodes(n, ignore_priority)) - enqueued
+ enqueued |= new
+ queue.extend([(n, child) for child in new])
def shortest_path(self, start, end, ignore_priority=None):
- paths = {None: []}
- for parent, child in self.bfs(start, ignore_priority):
- paths[child] = paths[parent] + [child]
- if child == end:
- return paths[child]
- return []
+ if start not in self:
+ raise KeyError(start)
+ elif end not in self:
+ raise KeyError(end)
+
+ paths = {None: []}
+ for parent, child in self.bfs(start, ignore_priority):
+ paths[child] = paths[parent] + [child]
+ if child == end:
+ return paths[child]
+ return None
def get_cycles(self, ignore_priority=None, max_length=None):
"""